/* =========================================================================
   THE SITE'S OWN FONTS
   =========================================================================
   Merriweather for headings, Noto Sans for text. Both are SHIPPED WITH THE
   SITE, in fonts/ next to this stylesheet, rather than relied upon to exist
   on the reader's computer. That is what makes the pages look the same on a
   university PC, a Mac and a phone - Bookman Old Style, used before, exists
   only on Windows, so everyone else saw a substitute.

   Both are under the SIL Open Font License: free to use, embed and pass on.

   SELF-HOSTED, NOT LOADED FROM GOOGLE. Fetching fonts from Google's servers
   would send every visitor's address to a third party - an avoidable data
   protection question for a European university site - and would add a
   dependency on someone else's uptime. These files are ours.

   Four faces each: regular, bold, italic and bold italic. The italics matter
   on this site, which uses them for chairs, authors, social events and the
   page titles; without a real italic the browser slants the upright face
   mechanically, which looks crude at heading size.

   'font-display: swap' means text appears immediately in a fallback and
   changes to the proper face once loaded, rather than the page sitting
   blank. Only the Latin range is included, which covers Italian accents and
   the punctuation used here, and keeps the files small. */
@font-face{font-family:'Merriweather';font-style:normal;font-weight:400;font-display:swap;
  src:url(../fonts/merriweather-400.woff2) format('woff2');}
@font-face{font-family:'Merriweather';font-style:normal;font-weight:700;font-display:swap;
  src:url(../fonts/merriweather-700.woff2) format('woff2');}
@font-face{font-family:'Merriweather';font-style:italic;font-weight:400;font-display:swap;
  src:url(../fonts/merriweather-400i.woff2) format('woff2');}
@font-face{font-family:'Merriweather';font-style:italic;font-weight:700;font-display:swap;
  src:url(../fonts/merriweather-700i.woff2) format('woff2');}

@font-face{font-family:'Merriweather';font-style:normal;font-weight:900;font-display:swap;
  src:url(../fonts/merriweather-900.woff2) format('woff2');}
@font-face{font-family:'Merriweather';font-style:italic;font-weight:900;font-display:swap;
  src:url(../fonts/merriweather-900i.woff2) format('woff2');}

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

@font-face{font-family:'Noto Sans Mono';font-style:normal;font-weight:400;font-display:swap;
  src:url(../fonts/notosansmono-400.woff2) format('woff2');}
@font-face{font-family:'Noto Sans Mono';font-style:normal;font-weight:700;font-display:swap;
  src:url(../fonts/notosansmono-700.woff2) format('woff2');}

@font-face{font-family:'Noto Sans';font-style:normal;font-weight:400;font-display:swap;
  src:url(../fonts/notosans-400.woff2) format('woff2');}
@font-face{font-family:'Noto Sans';font-style:normal;font-weight:700;font-display:swap;
  src:url(../fonts/notosans-700.woff2) format('woff2');}
@font-face{font-family:'Noto Sans';font-style:italic;font-weight:400;font-display:swap;
  src:url(../fonts/notosans-400i.woff2) format('woff2');}
@font-face{font-family:'Noto Sans';font-style:italic;font-weight:700;font-display:swap;
  src:url(../fonts/notosans-700i.woff2) format('woff2');}

/* =========================================================
   WEMDCD 2027 — stylesheet
   =========================================================

   ORIENTATION FOR A FRESH SESSION (read this first)
   ---------------------------------------------------
   This is a hand-coded site with no build step. It now uses PHP includes
   for the shared page furniture; there is no generator script and no
   framework.

   Site: 11 pages, each pulling in one shared header and footer:
     index.php (Overview/Welcome), venue.php, papers.php, program.php,
     registration.php, side-events.php, sponsors.php, news.php,
     plus the proceedings gate — login.php and proceedings.php,
     which carry class "page-proceedings" and are included in the shared
     card / typography / highlight selector lists alongside the others.
     Their own specific styling (access-code form, paper list, session
     notices) is in one block near the END of this file.

   SHARED MARKUP IS NO LONGER DUPLICATED. The title band, logos, nav menu,
   news ticker and footer live in includes/header.php and
   includes/footer.php, and the menu entries and ticker items live in
   includes/site-data.php. One edit there changes all 8 pages at once.
   (Before this change every page carried its own copy and the same edit
   had to be repeated eight times — the historical cause of most drift
   bugs in this project. Do not reintroduce per-page copies.)

   NAV DROPDOWNS: defined once, in includes/site-data.php. If a page
   adds/renames/removes a section id, update the matching dropdown entry
   there — one place, not eight. The `current` button highlight comes from
   $page_key at the top of each page matching a 'key' in that file.

   PAGE STRUCTURE per page: one <section class="hero"> (title + lead
   paragraphs) followed by one or more <section id="X" class="content-
   section"> blocks (each becomes an ivory rounded "card" — see the card
   rules below). Sections with class="content-section key-section" get a
   left accent bar (dark red) to visually highlight specific cards —
   this is applied selectively per explicit user request, not automatic.

   SPACING SCALE (current, as of this comment — check the actual values
   below since they've been tuned several times through user feedback):
     - line-height 1.55 (in-paragraph, unchanged throughout all tuning)
     - li margin-bottom 0.405rem (list items)
     - p margin-bottom 0.765rem (paragraphs)
     - a paragraph immediately followed by a <ul> gets margin-bottom
       0.405rem instead of 0.765rem, via `p:has(+ ul)`, so the gap above
       a list matches the gap between the list's own items (verified via
       exact pixel measurement, not assumed)
     - the Venue page's Attractions section (#Attractions) has its own,
       larger override (currently 1.8rem) since it's unusually dense with
       consecutive paragraphs and photo-rows — deliberately not tied to
       the base scale, so it won't move if the base spacing is retuned
       again unless explicitly asked.
   All three of the above (line-height / list / paragraph) were validated
   together via rendered comparison screenshots before being applied —
   if asked to retune again, build a quick side-by-side HTML preview
   using this same stylesheet before committing to new values, rather
   than guessing.

   ROOT FONT-SIZE is 92% (see html{} rule) — an 8% site-wide shrink
   applied early on. Nearly all spacing is in rem, so it cascades
   automatically; a few hardcoded px values (image widths, max-widths)
   were manually reduced 8% to match and are commented where relevant.

   CARD SYSTEM: section.content-section{} + the big shared selector list
   further down (.page-welcome section.content-section, .page-venue
   section.content-section, etc.) gives every content section on every
   "real content" page an ivory background, rounded corners, and
   consistent padding — tuned so the visual gap above the h2 title
   equals the gap below the last line of content (~40px at the time it
   was tuned, before the 8% shrink; re-measure rather than assume).

   BADGES: h1 = dark red pill/badge, upright. h2 = blue pill/badge,
   italic. Both share the same rounded/embossed visual language.

   TWO IMAGE CAROUSELS (logic lives in js/main.js, not here):
     1. Header background carousel — Pisa-only photos, sliding
        left-to-right, in #bgStrip. On every page, not only the Venue.
     2. Venue page's "Attractions" card ends with a second carousel,
        #tuscanyCarousel, cross-fading (not sliding) between random sets.
        How many it shows at once is decided HERE, by the stylesheet —
        one in portrait, two in landscape, four on a larger screen — and
        read back by the script.
   THEY NO LONGER HAVE SEPARATE POOLS. The lower carousel draws from the
   Tuscany photos AND the Pisa ones, so the two could collide by content.
   What stops a photo appearing top and bottom at once is a runtime
   register in js/main.js: each declares what it is showing and what it is
   about to show, and the banner always chooses first. Adding a photo to
   either list is therefore safe — do NOT reintroduce a rule about keeping
   the two sets disjoint, which is what this note used to say.

   IMAGE NAMING CONVENTION: `City_ShortDescription.jpg`, e.g.
   `Pisa_TorreGiorno.jpg`, `Siena_Duomo.jpg`. Established after a cleanup
   pass — when adding new photos, follow this pattern and pick a city
   prefix that's actually accurate (ask the user if genuinely ambiguous,
   e.g. a small comune near but distinct from Pisa).

   VENUE PAGE'S PHOTO+TEXT PATTERN (`.venue-photo-row` and friends,
   below): a photo sits beside a specific paragraph (or two photos flank
   one), while other paragraphs in the same card stay full-width. Photos
   can be `.square` (240x248) or `.portrait` (200x310), left- or right-
   aligned (`.reverse` flips it via flex order, not by changing DOM
   order — this keeps the mobile stacked layout consistent, since DOM
   order still puts the photo first when the row collapses to a column).
   `.align-top` is used when the paired paragraph is long, so the photo
   doesn't look oddly centered against a much taller text block.

   TESTING WORKFLOW used throughout this project (Playwright + a local
   http.server on port 8877, serving this folder) — always verify actual
   computed styles/positions via script rather than trusting a visual
   screenshot alone for anything measurement-sensitive (margins, gaps,
   widths); screenshots are for catching things numbers can't, like
   whether a crop still looks good.
   ========================================================= */

:root{
  /* palette */
  --navy:            #0a2342;
  --navy-deep:       #061633;
  --yellow:          #ffd400;
  /* A slightly lighter gold, used ONLY on the badges - the page titles and
     the section headings. They sit on saturated red and blue backgrounds
     where the deeper gold read as dull; the banner keeps --yellow, where it
     looks right against the dark navy.

     It sits between --yellow and the colour a hovered button paints
     (brightness(1.15) on --yellow gives #fff400), so it reads as brighter
     without becoming acidic on the blue section badges. */
  /* Halfway between the two: #ffe83a, which the badges used, and #ffd400,
     the deeper gold of the acronym. Channel by channel - red stays 255,
     green (232+212)/2 = 222, blue (58+0)/2 = 29. */
  --yellow-badge:    #ffd90e;   /* midway between the previous #ffde1d and the banner's #ffd400 */
  --yellow-shadow:   #8a6a00;
  --white:           #ffffff;
  --grey-light:      #d6d6d6;
  --green:           #1c7a3b;
  --nav-text:        ivory;
  --nav-text-active: #ffffff;
  --blue-btn-top:    #2f86c9;
  --blue-btn-mid:    #0f4f96;
  --blue-btn-bot:    #072850;
  --cyan:            #21f2ea;
  --bright-cyan:     #1fe9ff;
  --cyan-shadow:     #005f5c;
  --dark-red:        #7a0c0c;
  --dark-red-deep:   #4d0707;
  --ink:             #17202a;
  --paper:           #f6f7f9;
  --rule:            #e0e3e8;

  /* type */
  /* The fallbacks after each name are only for the instant before the font
     file arrives, or if it fails to load at all. */
  /* THE HEADING FACE AND ITS WEIGHT ARE SET HERE, IN TWO PLACES ONLY.
     --font-display picks the family; --heading-weight decides how heavily it
     is drawn. Merriweather's Black (900) and PT Serif's Bold (700) are both
     shipped, so switching between them is an edit to these two lines. */
  --font-display:    "PT Serif", Georgia, "Times New Roman", serif;
  --heading-weight:  700;

  /* PT Serif has narrower letterforms than the face it replaced, so the
     badges came out looking smaller at the same nominal size. Everything
     drawn in the heading face is scaled by this one figure, so the titles
     keep a consistent relationship to each other whatever it is set to. */
  --heading-scale:   1.1;
  --font-nav:     "Noto Sans", Tahoma, Geneva, Verdana, sans-serif;
  --font-util:    "Noto Sans", Arial, Helvetica, sans-serif;
  --font-body:    "Noto Sans", "Segoe UI", Arial, Helvetica, sans-serif;
  /* For the access-code field only. A FIXED-WIDTH face, so every character
     occupies the same room whatever it is: the box can then be sized for a
     known number of characters and will hold exactly that many, upper case
     or lower, which a proportional font cannot promise - "WWWW" is far wider
     than "iiii". Noto Sans Mono also matches the text face, and is narrow,
     so more of a code fits on a phone. */
  --font-code:    "Noto Sans Mono", ui-monospace, Consolas, "Liberation Mono", monospace;

  --fs-acronym:   4.28rem;   /* 3.75rem +20%, then -5%: +14% overall */
  --fs-fullname:  1.575rem;   /* 70% of acronym, then -10% to save header height */
  /* TIED TO THE ACRONYM, not set independently. The date line has to sit in a
     fixed relationship to the logos either side, and that only holds if the
     two lines keep the same proportions at every screen size. Set separately,
     the ratio drifted - 45% of the acronym on a desktop but 54% on a phone -
     and the careful alignment came apart as soon as the window narrowed. */
  --fs-dateloc:   calc(var(--fs-acronym) * 0.451);
  --fs-nav:       1.134rem;   /* ~50% of fullname, then +20%, then +5% */
}

/* ---------- reset ---------- */
*, *::before, *::after{ box-sizing: border-box; }
html{ margin:0; padding:0; height:100%; font-size: 92%; }   /* -8%, cascades through the whole site since nearly everything is rem/em-based */
body{
  margin:0;
  padding:0;
  display: flex;
  flex-direction: column;
  min-height: 100vh;
  font-family: var(--font-body);
  color: var(--ink);
  background: var(--paper);
  line-height: 1.55;
  -webkit-font-smoothing: antialiased;
}
img{ max-width:100%; display:block; }
a{ color: inherit; }
ul{ list-style:none; margin:0; padding:0; }
h1,h2,h3{ font-family: var(--font-display); font-weight: var(--heading-weight); }
:focus-visible{
  outline: 3px solid var(--cyan);
  outline-offset: 2px;
}

/* =========================================================
   HEADER — Title, Ribbon, Buttons, News (kept permanently visible while scrolling)
   ========================================================= */
.site-header{
  position: sticky;
  top: 0;
  z-index: 100;
  flex: 0 0 auto;
}

/* ---------- Title ---------- */
.band-title{
  background: var(--navy-deep);
  /* Vertical padding trimmed with the font, to take about 15% off the height
     of this band. The header is the site's biggest consumer of screen: on a
     phone in landscape the fixed areas were leaving barely 60px for the page
     itself. Horizontal padding is unchanged - only height is at issue. */
  padding: 0.38em 2rem;
}
.band-title .fullname{
  max-width: 1400px;
  margin: 0 auto;
  text-align: center;
}

/* ---------- Ribbon ---------- */
.band-ribbon{
  position: relative;
  background: var(--navy);
  overflow: hidden;
  min-height: 108px;    /* trimmed with the padding above */
}

.band-ribbon-bg{
  position:absolute; inset:0;
  overflow: hidden;
  z-index: 0;
}
.band-ribbon-bg img{
  position: absolute;
  top: 0;
  width: 20%;
  height: 100%;
  object-fit: cover;
  filter: saturate(1.3) brightness(1.12) contrast(1.06);
  transition: left 1.1s ease, opacity 1.1s ease;
  will-change: left, opacity;
}
.band-ribbon-scrim{
  position:absolute; inset:0;
  /* darkest behind the centered acronym, brightening more clearly towards both edges */
  background:
    linear-gradient(90deg, rgba(6,16,38,0.08) 0%, rgba(6,16,38,0.58) 50%, rgba(6,16,38,0.08) 100%),
    linear-gradient(180deg, rgba(6,16,38,0.20) 0%, rgba(6,16,38,0.03) 35%, rgba(6,16,38,0.24) 100%);
  z-index: 1;
}

.band-ribbon-inner{
  position: relative;
  z-index: 2;
  display:flex;
  align-items:center;
  justify-content:space-between;
  gap: 1.5rem;
  /* Trimmed to take about 15% off the height of the band (170px -> 146px on
     a desktop). Most of the band is the content itself - the logos and the
     two lines of title - so only the padding was available to give: it went
     from 1.25rem to 0.45rem to find that much. The slideshow is
     the largest single part of the fixed area at the top of every page - on
     a phone held sideways the header was leaving barely a fifth of the
     screen for the page itself. */
  padding: 0.45rem 2rem 0.45rem 2rem;
  min-height: 108px;
  /* NO NUDGE. There used to be a translateY(-6px) here, moving the logos and
     title up but NOT the photographs behind them - which is exactly why the
     block looked as though it were riding high over the slideshow. The
     content is simply centred now. */
}

.ribbon-left{
  display:flex;
  flex-direction:column;
  /* The date line is pulled up close under the acronym, so that the bottom of
     its letters meets the bottom edge of the logos either side. It used to
     hang 20px below them, and being the lowest thing in the band it was
     setting the height of the whole slideshow area - so closing this gap
     both tidies the alignment and shortens the header.

     Measured, not guessed: the figure is the distance the letters actually
     painted below the logos, expressed against --fs-acronym so it holds if
     the title size changes. */
  gap: 0;
  flex: 1 1 auto;
  min-width: 0;              /* allow children to shrink for the fit-to-width JS */
  text-align: center;
}

/* The logos beside the title are taller than the letters, and the row centres
   everything vertically, so the text floated about a fifth of a letter-height
   above them. This drops the text block that sits BETWEEN the two logos -
   .ribbon-left, holding the acronym and the date line together - so that the
   top of the lettering meets the top of the logos. It must not be applied to
   an outer container: the logos are inside those, so everything would move
   together and nothing would change.

   THE FIGURE IS TINY, AND THAT IS CORRECT. It looks as though the text needs
   dropping by about a fifth of its height, but only if you measure the text's
   LINE BOX - which reaches up to the ascender, well above the capitals. What
   the eye sees is where the letters start painting, and that is already some
   20px lower. Measuring the line box gave 0.298 and put the capitals halfway
   down the logos; measuring the painted pixels gives this.

   Expressed as a fraction of --fs-acronym rather than as a fixed number of
   pixels, so it follows the title if its size is ever changed again. Desktop
   only: on a phone the logos sit above the title rather than beside it, and
   there is nothing to align to. */
/* Applied wherever the logos sit BESIDE the title, which is down to 621px -
   not only on a desktop. Scoped to 901px before, it left phones in landscape
   (844px wide, logos still beside the text) with the title sitting a few
   pixels low against them. At 620px and below the layout stacks and there is
   nothing to align to, so the rule stops there. */
@media (min-width: 621px){
  .ribbon-left{ position: relative; top: calc(var(--fs-acronym-actual, var(--fs-acronym)) * -0.1034); }
}

.acronym, .fullname, .dateloc{
  margin: 0;
  width: 100%;
  overflow: hidden;
  white-space: nowrap;       /* kept on one line; JS shrinks font-size to fit */
}

.acronym{
  font-family: var(--font-display);
  font-weight: 700;
  font-size: var(--fs-acronym);
  color: var(--yellow);
  /* IN EM, NOT PIXELS. A fixed 7.5px was about an eighth of the letter height
     on a desktop but nearly a quarter of it on a phone, where the title is
     half the size - which is why the mobile banner looked loosely spaced.
     Expressed as a fraction of the letter height it stays in proportion at
     any screen size. 0.119em is what 7.5px amounted to on the desktop. */
  letter-spacing: 0.119em;
  /* AND NUDGED RIGHT BY HALF A SPACE. Letter-spacing is added after EVERY
     character, the last one included, so the line carries a phantom space
     past the final "7". Centring the line therefore leaves the LETTERS
     sitting half a space to the left - 11px out on a desktop, plainly
     visible against the logos either side.

     text-indent, not a negative margin: the phantom space is inside the
     centred line, so trimming the box does nothing (tried, no effect). On
     centred text an indent shifts the visible text by HALF its value, so an
     indent of one letter-space moves it right by half a space - exactly the
     amount it was out. */
  text-indent: 0.119em;
  text-shadow:
    1px 1px 0 var(--yellow-shadow),
    2px 2px 0 var(--yellow-shadow),
    3px 3px 0 #5c4700,
    4px 5px 8px rgba(0,0,0,0.55);
}
.acronym a{
  color: inherit;
  font: inherit;
  letter-spacing: inherit;
  text-shadow: inherit;
  text-decoration: none;
}

.fullname{
  font-family: var(--font-display);
  font-style: italic;
  font-weight: 700;
  font-size: var(--fs-fullname);
  /* A little air between the letters, in em so it stays in proportion at any
     size. Deliberately less than the acronym below it (0.119em): the title is
     a long line, and spacing it as widely would read as slack rather than
     deliberate, and would blur the difference between the two bands.

     0.045 rather than 0.06 for a second reason as well. The line is fitted to
     one line by shrinking the font (see fitOneLine in js/main.js), so on a
     phone extra letter-spacing is paid for in smaller letters: 0.06em cost
     about half a pixel of type size. Wider spacing is free on a desktop,
     where the line has room to spare, but not on a narrow screen. */
  letter-spacing: 0.045em;
  text-indent: 0.045em;      /* centred on the letters, as the other lines */
  color: var(--yellow);
  text-shadow:
    1px 1px 0 var(--yellow-shadow),
    2px 2px 0 #5c4700,
    3px 4px 6px rgba(0,0,0,0.5);
}
.fullname a{
  color: inherit;
  font: inherit;
  font-style: inherit;
  text-shadow: inherit;
  text-decoration: none;
}
.fullname sup{
  font-size: 0.62em;
  top: -0.55em;
}

.dateloc{
  margin-top: calc(var(--fs-acronym-actual, var(--fs-acronym)) * -0.0856);
  font-family: var(--font-nav);   /* Tahoma-style, distinct from the serif display lines */
  font-weight: 700;
  font-size: var(--fs-dateloc);
  letter-spacing: 0.079em;   /* in em for the same reason as the acronym */
  text-indent: 0.079em;      /* centred on the letters, as the acronym is */
  color: var(--bright-cyan);
  text-shadow:
    1px 1px 0 var(--cyan-shadow),
    2px 2px 0 #003836,
    3px 4px 6px rgba(0,0,0,0.55);
}
.dateloc a{
  color: inherit;
  font: inherit;
  letter-spacing: inherit;
  text-shadow: inherit;
  text-decoration: none;
}

/* the logos are now wrapped in <a> tags (for the click-through links); the
   anchor itself needs to be the non-shrinking flex item now, since it's
   what actually sits in the row -- otherwise it would default to
   shrinking and the img's own flex:0 0 auto below would have no effect */
 /* The two logo plates. One is a plain link; the other is a <span> holding
     two links, one per half - so they are matched by a class rather than by
     being anchors, which only one of them now is. */
.band-ribbon-inner > .ribbon-logo{
  flex: 0 0 auto;
  display: flex;
  line-height: 0;
}
/* both logos sit at the far edges of the band, vertically centred against
   the acronym + date/location block via align-items:center on the row */
.acronym-logo, .unipi-logo{
  flex: 0 0 auto;
  width: auto;
  height: calc(var(--fs-acronym) * 1.35);  /* sane default before JS fine-tunes it */
  border-radius: 6px;
  box-shadow: 0 2px 10px rgba(0,0,0,0.45);
  background: #fff;   /* both logos keep their white plate, for contrast against the dark band */
}

/* THE TWO HALVES OF THE UNIVERSITY PLATE.

   The picture is one file; these are two invisible links laid over it, the
   left one leading to the University and the right to the DESTEC department.
   46.1% is where the dividing rule falls in the image, measured from the file
   itself, so the boundary sits exactly on the line a reader can see.

   They are positioned as percentages, so they follow the plate at every size
   with nothing to recompute. inset gives top and bottom in one figure.

   The plate keeps its own rounded corners; these inherit them at the outer
   edges so a press cannot highlight a square corner over a round one. */
.unipi-pair, .ieee-pair{ position: relative; display: inline-block; line-height: 0; }
.unipi-pair .logo-half, .ieee-pair .logo-half{
  position: absolute;
  top: 0;
  bottom: 0;
  display: block;
}
/* Each boundary is where that file's own rule is drawn, measured from the
   image - 58.5% on the University plate, 59.3% on the IEEE one. They are
   close but not equal, and using one figure for both would put at least one
   boundary off its line. */
.logo-half-unipi { left: 0;      width: 58.5%; border-radius: 6px 0 0 6px; }
.logo-half-destec{ left: 58.5%; right: 0;      border-radius: 0 6px 6px 0; }
.logo-half-ies   { left: 0;      width: 59.3%; border-radius: 6px 0 0 6px; }
.logo-half-ieee  { left: 59.3%; right: 0;      border-radius: 0 6px 6px 0; }
/* Nothing is drawn for them at rest; under a pointer the half being aimed at
   lifts a little so it is clear which of the two will be followed. */
@media (hover: hover) and (pointer: fine){
  .unipi-pair .logo-half:hover,
  .ieee-pair  .logo-half:hover{ background: rgba(0,60,140,0.10); }
}
.unipi-pair .logo-half:focus-visible,
.ieee-pair  .logo-half:focus-visible{
  outline: 2px solid var(--yellow);
  outline-offset: -2px;
}

/* ---------- Buttons ---------- */
.band-buttons{
  background: var(--navy-deep);
  /* UNEQUAL ON PURPOSE, TO LOOK EQUAL.

     The buttons carry a solid 4px shadow along their lower edge, which the
     eye reads as part of the button, not as background. Padding that is
     equal top and bottom therefore looks bottom-heavy: measured it was
     4.8px of clear space above and 4.8 below, but only 0.8 of that lower
     space was actually visible.

     The bottom padding therefore carries a little extra to pay for it. The
     figures come from counting PAINTED PIXELS, not from arithmetic: the
     shadow's visible reach turned out to be under 4px, so a calculated
     correction over-shot and left the lower gap too large instead. The band
     is also 5% deeper than before. */
  padding: 0.663rem 1.5rem 0.717rem 1.5rem;
  position: relative;
  z-index: 40;
}

.nav-inner{
  display:flex;
  align-items:center;
  justify-content:center;
  max-width: 1280px;
  margin: 0 auto;
}

.nav-buttons{
  /* The row carries no text of its own, only buttons. Left at a normal line
     height it reserved room for a descender BELOW the buttons - 5.8px that
     nothing occupied - so the band's symmetric padding produced 8.8px of
     space above the buttons and 14.6px below. Zeroing it lets the padding
     mean what it says. */
  line-height: 0;
  display:flex;
  justify-content:center;
  align-items:stretch;
  /* 1.15rem, using the width recovered from the LogIn button's reserve.
     NOT the maximum that fits: at 1.25rem the bar came to exactly the width
     available on the narrowest window that shows it - no margin at all, and
     a slightly different font rendering would have pushed it over. This
     leaves about 15px in hand. */
  gap: 1.15rem;
  flex: 1;
  flex-wrap: nowrap;
}

.nav-item{ position:relative; }

/* The proceedings button is an <a>, not a <button>, because it navigates
   rather than opening a dropdown. Anchors bring their own defaults - the
   underline, the visited colour, inline layout - so they are cleared here.
   Everything else it needs is in .nav-btn below, which it also carries. */
a.nav-btn{
  display: inline-block;
  text-decoration: none;
  text-align: center;
  line-height: normal;
}
a.nav-btn:visited{ color: var(--nav-text); }
.nav-item.current a.nav-btn:visited{ color: var(--yellow); }
/* the countdown must not change width as the digits change, or the whole
   menu bar shifts every second */
/* The width is HELD FIXED so the bar does not shift every second while a
   countdown is running - but 5.5em reserved more than any label needs. The
   widest this button ever shows is "LogIn" itself - the whole button measures
   80px that way, against 73px for a countdown - so the reserve must be about
   4.85em. 4.4em was tried and was NOT enough: it stopped the button jittering
   between one countdown value and the next, but the button still jumped by
   7px the moment "LogIn" turned into "24 s". The width saved against the
   original 5.5em went into the gaps between the buttons.

   RE-MEASURE THIS IF THE MENU FONT CHANGES, and keep it above the widest
   label: too small and the bar will jitter once a second during a session. */
.nav-btn-login{ min-width: 4.85em; font-variant-numeric: tabular-nums; }

/* The proceedings button while a session is running: dark green, so the
   fact that you are signed in reads at a glance from anywhere on the page.
   It is the ONLY green in the menu bar and that is the point - blue means
   "sign in", green means "signed in, this much time left". js/main.js adds
   and removes this class; the button returns to the standard blue by
   itself the moment the countdown reaches zero.

   The gradient mirrors the shape of the standard .nav-btn one (light top,
   dark bottom, solid shadow beneath) so it reads as the same button in a
   different colour rather than as a different component. */
/* SWITCHED OFF WITH THE PROGRAMME. The button keeps its place in the bar but
   is plainly not available: muted, flat, and carrying no href, so there is no
   pointer and nothing to click. It is not hidden, because a menu bar that
   gains and loses a button between phases is more confusing than one showing
   something that is not ready yet. */
.nav-btn.nav-btn-off,
.nav-btn.nav-btn-off:hover,
.nav-btn.nav-btn-off:active,
.nav-btn.nav-btn-off:focus{
  background: linear-gradient(180deg, #6a6f78 0%, #575c64 55%, #43474e 100%);
  box-shadow:
    inset 0 1px 0 rgba(255,255,255,0.12),
    inset 0 -2px 4px rgba(0,0,0,0.28),
    0 4px 0 #43474e,
    0 7px 12px rgba(0,0,0,0.3);
  color: rgba(255,255,255,0.72);
  transform: none;
  filter: none;
  cursor: default;
}

/* THE COUNTING STATE IS A DISPLAY, NOT A CONTROL.

   While a session is running the button only reports how much time is left.
   It used to be clickable, to reset the clock - but any ordinary use of the
   site already resets it (see ping.php), so clicking was a duplicate of
   something that happens by itself. It is now inert: the server omits the
   href, and the rules below cancel the hover and pressed effects that every
   other menu button has, so nothing invites a click that would do nothing.

   The raised look is kept at rest, so it still reads as part of the menu bar
   rather than as a gap in it. The lift-on-hover belongs to the blue "LogIn"
   state, which IS a control. */
.nav-btn.nav-btn-counting,
.nav-btn.nav-btn-counting:hover,
.nav-btn.nav-btn-counting:active,
.nav-btn.nav-btn-counting:focus{
  background: linear-gradient(180deg, #2f9c57 0%, #1c7a3b 55%, #0e4a22 100%);
  box-shadow:
    inset 0 1px 0 rgba(255,255,255,0.18),
    inset 0 -2px 4px rgba(0,0,0,0.35),
    0 4px 0 #0e4a22,
    0 7px 12px rgba(0,0,0,0.4);
  transform: none;      /* no lift, no press */
  filter: none;         /* no brightening */
  cursor: default;      /* an arrow, not a hand */
  color: var(--nav-text);
}
/* When the LogIn button IS the current page's button - i.e. you are looking
   at login.php - the site's standard dark-red "you are here" highlight wins
   over the green. Every page's own button is red, without exception; that
   rule is what makes the menu bar readable at a glance, and the green is not
   worth breaking it for. The green returns as soon as you navigate away. */
.nav-item.current .nav-btn.nav-btn-counting,
.nav-item.current .nav-btn.nav-btn-counting:hover,
.nav-item.current .nav-btn.nav-btn-counting:active{
  background: linear-gradient(180deg, var(--dark-red) 0%, var(--dark-red-deep) 100%);
  color: var(--yellow);
  box-shadow:
    inset 0 1px 0 rgba(255,255,255,0.18),
    inset 0 -2px 4px rgba(0,0,0,0.35),
    0 4px 0 var(--dark-red-deep),
    0 7px 12px rgba(0,0,0,0.4);
}

.nav-btn{
  position: relative;
  overflow: hidden;
  font-family: var(--font-nav);
  font-weight: 700;
  font-size: var(--fs-nav);
  letter-spacing: 0.6px;
  color: var(--nav-text);
  text-shadow: 1px 1px 0 rgba(0,0,0,0.8);
  background: linear-gradient(180deg, var(--blue-btn-top) 0%, var(--blue-btn-mid) 55%, var(--blue-btn-bot) 100%);
  border: 1px solid rgba(255,255,255,0.12);
  border-radius: 14px;
  /* Less air above and below than before. The labels are a capital followed
     by lower-case letters with no descenders, so the space under the baseline
     had nothing to balance and the button read as much taller than its text.
     The sides are unchanged: that is where the bar has no room to spare. */
  /* ONE SIZE IN EVERY CONTEXT. These buttons were three different heights:
     31.3px in the bar on a desktop, 29.7 in the bar when a phone is held
     sideways, and 35.0 when packed into the Menu panel - the same control
     changing size according to how it happened to be shown. The vertical
     figure is set here and nowhere else. */
  padding: 0.19em 0.84em;
  cursor: pointer;
  box-shadow:
    inset 0 1px 0 rgba(255,255,255,0.18),
    inset 0 -2px 4px rgba(0,0,0,0.35),
    0 4px 0 var(--blue-btn-bot),
    0 7px 12px rgba(0,0,0,0.4);
  transform: translateY(0) scale(1);
  transition: transform 0.16s cubic-bezier(.34,1.4,.64,1), box-shadow 0.16s ease, filter 0.16s ease, color 0.16s ease;
  white-space: nowrap;
}
.nav-btn::before{
  content: "";
  position: absolute;
  inset: 0;
  background: linear-gradient(180deg, rgba(255,255,255,0.38) 0%, rgba(255,255,255,0.10) 42%, rgba(255,255,255,0) 62%);
  border-radius: inherit;
  pointer-events: none;
}
/* The same reasoning as the "Menu" button above: a tapped button would
   otherwise keep the pressed look after its list had been closed. The open
   state comes from .open, which the script controls; the hover half is split
   into the pointer-only rule below. */
.nav-item.open .nav-btn{
  color: var(--nav-text-active);
  background: linear-gradient(180deg, var(--dark-red) 0%, var(--dark-red-deep) 100%);
  filter: brightness(1.15);
  transform: translateY(-3px) scale(1.03);
  box-shadow:
    inset 0 1px 0 rgba(255,255,255,0.28),
    inset 0 -2px 4px rgba(0,0,0,0.35),
    0 6px 0 var(--dark-red-deep),
    0 12px 18px rgba(0,0,0,0.45);
}
/* The hover half, for pointer devices only - see the note above the open
   state. Written out rather than added to that selector so the two cannot be
   accidentally recombined. */
@media (hover: hover) and (pointer: fine){
  .nav-btn:hover{
    color: var(--nav-text-active);
    background: linear-gradient(180deg, var(--dark-red) 0%, var(--dark-red-deep) 100%);
    filter: brightness(1.15);
    transform: translateY(-3px) scale(1.03);
    box-shadow:
      inset 0 1px 0 rgba(255,255,255,0.28),
      inset 0 -2px 4px rgba(0,0,0,0.35),
      0 6px 0 var(--dark-red-deep),
      0 12px 18px rgba(0,0,0,0.45);
  }
}
.nav-btn:active{
  transform: translateY(2px) scale(0.99);
  box-shadow:
    inset 0 1px 0 rgba(255,255,255,0.12),
    inset 0 -1px 3px rgba(0,0,0,0.35),
    0 2px 0 var(--blue-btn-bot),
    0 3px 6px rgba(0,0,0,0.35);
}
.nav-item.current .nav-btn{
  background: linear-gradient(180deg, var(--dark-red) 0%, var(--dark-red-deep) 100%);
  color: var(--yellow);
  outline: 2px solid var(--yellow);
  outline-offset: 2px;
  box-shadow:
    inset 0 1px 0 rgba(255,255,255,0.18),
    inset 0 -2px 4px rgba(0,0,0,0.35),
    0 4px 0 var(--dark-red-deep),
    0 7px 12px rgba(0,0,0,0.4);
}

/* dropdown */
.dropdown{
  position:absolute;
  top: calc(100% + 10px);
  left: 50%;
  transform: translateX(-50%) translateY(-6px);
  width: max-content;   /* shrink-wrap to the longest item, so its own left/right padding stays symmetric */
  background: linear-gradient(180deg, var(--blue-btn-bot) 0%, var(--blue-btn-mid) 55%, var(--blue-btn-top) 100%);
  border-radius: 8px;
  box-shadow:
    inset 0 1px 0 rgba(255,255,255,0.22),
    inset 0 -2px 5px rgba(0,0,0,0.35),
    0 6px 0 var(--blue-btn-bot),
    0 14px 26px rgba(0,0,0,0.42);
  padding: 0.4rem;
  opacity: 0;
  visibility: hidden;
  pointer-events: none;
  transition: opacity 0.15s ease, transform 0.15s ease, visibility 0.15s;
  z-index: 60;
}
.dropdown::before{
  content:"";
  position:absolute;
  top:-6px; left:50%;
  transform: translateX(-50%) rotate(45deg);
  width:12px; height:12px;
  background: var(--blue-btn-mid);   /* a gradient can't render cleanly on a tiny rotated square, so use its uniform middle tone instead */
}
.dropdown a{
  display:block;
  font-family: var(--font-nav);
  font-weight: 700;
  font-size: 0.92rem;
  color: var(--yellow);
  text-shadow: 1px 1px 0 rgba(0,0,0,0.35);
  text-decoration:none;
  /* THE SAME SPACING AS ON A PHONE, and an explicit line height.

     The row of buttons is set to line-height:0 so that the space above and
     below them means what it says - but that cascades into these links,
     which carry text. Without a line height of their own the entries
     collapsed to 10px on a desktop and ran into one another, while the
     phone rules happened to set one and looked right. */
  padding: 0.319em 1em;
  line-height: 1.2;
  border-radius: 6px;
}
.dropdown a:hover, .dropdown a:focus-visible{
  background: rgba(255,255,255,0.18);
  color: #ffffff;
}

/* dropdowns open on click (not hover) so they never fight with cursor
   movement toward the news band; same behaviour on desktop and mobile */
.nav-item.open .dropdown{
  opacity:1; visibility:visible; pointer-events:auto;
  transform: translateX(-50%) translateY(0);
}

.hamburger{
  display:none;
  background: transparent;
  border: 2px solid var(--cyan);
  color: var(--cyan);
  font-size: 1.3rem;
  line-height:1;
  padding: 0.4em 0.6em;
  border-radius: 8px;
  cursor:pointer;
}

/* ---------- News ---------- */
/* THE "MENU" BUTTON BESIDE THE NEWS RIBBON.

   Shown WHEREVER THE COMPACT MENU IS USED - below 1024px, and in landscape
   only below 820px, where the whole row of buttons no longer fits. It
   replaced the hamburger, which sat alone on a band of its own and cost a
   whole line of screen for one small square. This shares the news ribbon's
   line instead, and says what it does in a word rather than in a symbol.

   Deliberately FLAT - no raised edge, no shadow, none of the moulding the
   menu buttons have. Those look like keys to press because pressing them
   takes you somewhere; this one opens a panel over the page, and a plain
   panel of colour that lightens under the finger says that better. */
.band-news-row{
  display: flex;
  align-items: stretch;      /* the button matches the ribbon's height exactly */
}
.band-news-row > .band-news{ flex: 1 1 auto; min-width: 0; }

.menu-button{
  display: none;             /* switched on by the max-width:1024px rule below,
                                and off again in landscape at 820px and up */
  flex: 0 0 auto;
  align-items: center;
  font-family: var(--font-nav);
  font-weight: 700;
  font-size: var(--fs-nav);
  letter-spacing: 0.6px;
  color: var(--white);
  /* The same blue as the menu buttons, but FLAT - their middle tone, without
     the gradient that gives them their moulded look. It reads as one of the
     family without pretending to be a key that can be pressed down. */
  background: var(--blue-btn-mid);
  border: 0;
  /* THE SPACE EITHER SIDE OF THE WORD, set HERE so it applies wherever the
     button is shown.

     It used to live in a rule for narrow screens held upright, while the
     button itself is shown on any screen using the compact menu - so on a
     tablet held upright, and on a phone held sideways, the word sat hard
     against both edges with no margin at all.

     0.645em rather than the 0.44 that makes the four gaps equal on paper:
     the text box includes leading above and below but hugs the letters at
     the sides, so equal padding leaves the word looking pinched. Measured in
     painted pixels, this gives about 12px on every side. */
  padding: 0 0.645em;
  cursor: pointer;
  -webkit-appearance: none;
  appearance: none;
}
/* THE BACKGROUND NEVER CHANGES - only the word does. A block of dark blue
   that stayed dark blue is what separates this control from the red ribbon
   beside it; changing its colour on hover blurred that division just when
   the reader was looking at it. The word turns yellow instead, which is the
   site's colour for "this is the one you are on" and needs no explanation. */
.menu-button:focus-visible,
.menu-button[aria-expanded="true"]{
  color: var(--yellow);
  background: var(--navy-deep);
  outline: none;
}

/* HOVER ONLY WHERE THERE IS SOMETHING TO HOVER WITH.

   A finger cannot hover. What a touch browser does instead is leave the last
   tapped element in its :hover state until something else is tapped - so the
   "Menu" button stayed dark with yellow lettering after the panel had been
   closed again, looking as though the menu were still open. The button that
   says what state the menu is in was reporting the wrong one.

   The open state is carried by aria-expanded, which is set by the script and
   is true only while the panel is open. Hover is now scoped to devices that
   really have a pointer, so it cannot linger where it means nothing. */
@media (hover: hover) and (pointer: fine){
  .menu-button:hover{
    color: var(--yellow);
    background: var(--navy-deep);
    outline: none;
  }
}


/* THE SECTION LISTS OPEN BESIDE THE BUTTONS IN BOTH ORIENTATIONS.

   This was written for a phone held upright and helps even more when it is
   turned: landscape has width to spare and very little height, which is
   exactly the trade this makes. */
@media (max-width: 1024px){
  /* NO "position: relative" ON THE PANEL. It was added to give the list
     something to be positioned against - but the panel is itself absolutely
     positioned, which already makes it one. Setting it to relative put it
     back into the flow: it pushed the news ribbon down the page and appeared
     ABOVE the button that opened it. */
  .nav-item.open .dropdown{
    position: absolute;
    left: var(--dd-left, 55%);
    top: var(--dd-top, 0.5rem);
    right: auto;
    /* AS WIDE AS ITS LONGEST ENTRY, like the dropdowns on a desktop. Made to
       fill the space instead, it came out 64px across and nearly every entry
       broke over two lines. */
    width: max-content;
    max-width: var(--dd-maxw, 14rem);
    margin-top: 0;
    z-index: 3;
    /* the raised, gradient panel it has elsewhere - the flat bordered box the
       mobile rules gave it looked like a different component */
    background: linear-gradient(180deg, var(--blue-btn-bot) 0%, var(--blue-btn-mid) 55%, var(--blue-btn-top) 100%);
    border: 0;
    border-radius: 8px;
    box-shadow:
      inset 0 1px 0 rgba(255,255,255,0.22),
      inset 0 -2px 5px rgba(0,0,0,0.35),
      0 6px 0 var(--blue-btn-bot),
      0 14px 26px rgba(0,0,0,0.42);
  }
  /* ROOM TO BREATHE between the entries. Stacked at their natural line
     height they ran together, with no clear gap between one and the next. */
  /* only the wrapping differs on a phone; the spacing itself is now the
     same everywhere and lives in the base rule above */
  .nav-item.open .dropdown a{ white-space: normal; }
}

/* WHEREVER THE COMPACT MENU IS USED, its control is the "Menu" button in the
   news ribbon - not only when the phone is held upright.

   Scoped to portrait before, it left a gap: a window between about 800 and
   820px wide in landscape got the compact menu but NOT the button, so the
   old hamburger reappeared on a band of its own, 59px tall and holding
   nothing else. The landscape rule further down shows the whole row of
   buttons instead and switches this off again. */
@media (max-width: 1024px){
  .menu-button{ display: inline-flex; }
  /* AND THE WORD "News :" GOES, wherever that button appears.

     The red band and the scrolling headline already say what the line is, and
     the word was spending 52px of a ribbon that has the "Menu" button to fit
     as well. Worse, the label does not scroll: on a tablet held upright it
     sat still beside Menu while the news itself had less room to move
     through, so the part that carries the information was the part that
     suffered.

     PAIRED WITH THE BUTTON DELIBERATELY. This declaration sits in the same
     rule that shows the button, and the one that hides it again restores the
     word - so the two can never drift apart into a state where the ribbon
     carries both. */
  .news-label{ display: none; }
  /* and the band that used to hold the hamburger has nothing left to hold */
  .band-buttons{ padding-top: 0; padding-bottom: 0; min-height: 0; }

  /* ---- THE PANEL IS ONLY AS BIG AS WHAT IS IN IT ----
     WHEREVER THE MENU BUTTON APPEARS, which is the point of putting this
     here. It was written twice before - once for a phone held upright, once
     for a phone held sideways - and the case in between, a TABLET held
     upright, was never given it: from 641 to 1024px the panel was still a
     full-width slab, leaving up to 873px of empty dark blue beside four
     buttons. Split-screen windows had the same fault for the same reason.
     Written once, beside the button it belongs to, there is no third case to
     forget.

     ONE GAP EVERYWHERE - 1.15rem - as the panel's padding, between the
     buttons, and between the last column and the section list that opens
     beside it. The height and the exact width come from js/main.js, which
     measures what is actually on show; --panel-fit is the flag that tells it
     this arrangement is in use.

     max-width keeps it on the screen if the widest button ever grows beyond
     what the window can hold. */
  .nav-buttons.open{
    right: auto;
    width: max-content;
    max-width: calc(100vw - 1.15rem);
    padding: 1.15rem;
    gap: 1.15rem;
    --panel-fit: 1;
  }
  .nav-buttons.open .nav-item{ width: auto; }
}

.band-news{
  display:flex;
  align-items:center;
  background: var(--dark-red);
  background-image: linear-gradient(180deg, var(--dark-red) 0%, var(--dark-red-deep) 100%);
  color: var(--white);
  text-decoration:none;
  /* A tenth shallower than it was (0.5rem). Set here rather than per screen:
     the reduction was applied first only on a desktop, then only in portrait,
     and was silently lost from the desktop when a duplicate rule was tidied
     away - so landscape kept the old height and nobody noticed. One value,
     one place. */
  padding: 0.36rem 2rem;
  gap: 1rem;
  overflow:hidden;
}
.news-label{
  font-family: var(--font-nav);
  font-weight:700;
  font-style: italic;
  font-size: var(--fs-nav);
  color: var(--white);
  white-space:nowrap;
  flex-shrink:0;
}
.news-ticker-viewport{
  flex:1;
  overflow:hidden;
  position:relative;
  height: 1.85rem;   /* matches the taller Venue-page-sized news text below */
}
.news-ticker-track{
  position:absolute;
  white-space:nowrap;
  display:inline-flex;
  gap: 4rem;
  animation: ticker 28s linear infinite;
  font-family: var(--font-util);
  font-weight: 700;
  font-size: 1.15rem;   /* matches the Venue page's body text size */
}
.band-news:hover .news-ticker-track{ animation-play-state: paused; }

/* THE BUTTON FOR THE PAGE YOU ARE ON DOES NOT LIFT.

   Every other button rises a little under the pointer, which is the site's
   way of saying "this will take you somewhere". For the current page it will
   not - you are already there - so the promise is not kept and the movement
   is misleading.

   It still brightens, so the pointer is acknowledged. And with the margins
   above and below the buttons now equal and tight, a 3px lift left the
   outline almost touching the top edge of the band, which read as a glitch
   rather than an effect. */
.nav-item.current .nav-btn:focus{ transform: none; }
@media (hover: hover) and (pointer: fine){
  .nav-item.current .nav-btn:hover{ transform: none; }
}

/* ON A DESKTOP the menu buttons and the news ribbon are each about a tenth
   shorter. Both are fixed furniture at the top of every page, and every pixel
   they give back is one the page itself can use. Scoped to pointer devices:
   on a touch screen the buttons need to stay comfortably tappable, so the
   smaller sizes are not applied there. */
@media (min-width: 1025px){
  /* the button height is set once in the base rule; nothing to add here */
}


@keyframes ticker{
  from{ transform: translateX(0); }
  to{ transform: translateX(-50%); }
}

/* =========================================================
   MAIN CONTENT
   ========================================================= */
.page-main{
  flex: 1 0 auto;           /* fills remaining space so the footer sticks to the bottom */
  width: 100%;
  background-color: var(--t-bg, var(--paper));
  transition: background-color 0.2s ease;
}
.page-main-inner{
  max-width: 994px;   /* -8% from 1080px */
  margin: 0 auto;
  /* The top figure is tuned with the badge below it: the space above the
     badge is 120% of the space beneath it, and that in turn is 150% of the
     gap between two paragraphs. Set in the shorthand, because a padding-top
     written above it would simply be overwritten here. */
  padding: 1.232rem 1.5rem 4rem;
}

.hero{
  text-align:left;
  padding: 0.988rem 0 1.2rem;   /* bottom now matches margin-bottom below */
  margin-bottom: 1.2rem;   /* -40% from 2rem */
}
.hero h1{
  font-size: 2.1rem;
  color: var(--t-heading, var(--navy));
  margin: 0 0 0.4rem;
}
.hero p.lead{
  font-family: var(--font-body);
  font-size: 1.1rem;
  color: var(--t-lead, #3a4552);
  max-width: 68ch;
  margin: 0 0 0.765rem;
}
.hero p.lead:last-child{
  margin-bottom: 0;   /* avoid stacking on top of .hero's own bottom padding/margin */
}

section.content-section{
  margin: 0 0 2.6rem;
  scroll-margin-top: 1rem;
}
/* Card treatment, now site-wide: each section gets its own card -- ivory
   background, rounded corners, matching the News page's article-card look.
   The left accent bar is off by default; .key-section adds it back for
   specific sections that should stand out (currently used on Venue only). */
.page-welcome section.content-section,
.page-venue section.content-section,
.page-papers section.content-section,
.page-proceedings section.content-section,
.page-program section.content-section,
.page-registration section.content-section,
.page-side-events section.content-section,
.page-sponsors section.content-section{
  background: ivory;
  border-radius: 15px;   /* +50% from 10px */
  padding: 1.975rem 2.5rem 1.5rem;   /* top/left/right increased so their total visual gap (incl. the h2's own margin-top) matches the 40px gap measured below the last line of text; bottom left as the reference */
}
.page-welcome section.content-section.key-section,
.page-venue section.content-section.key-section,
.page-papers section.content-section.key-section,
.page-proceedings section.content-section.key-section,
.page-program section.content-section.key-section,
.page-registration section.content-section.key-section,
.page-side-events section.content-section.key-section,
.page-sponsors section.content-section.key-section{
  border-left: 6px solid #8a1414;
}
/* Sponsors page: logo on the left, description on the right, sharing the
   card's existing padding. Falls back to a stacked column on narrow
   viewports so the logo never gets squeezed alongside long text. */
.page-sponsors section.sponsor-card{
  display: flex;
  align-items: center;
  gap: 2rem;
  min-height: 140px;   /* matches AddToShape's natural height; text-heavy cards can still grow taller */
}
/* the logo is now wrapped in <a> (clickable link to the sponsor's site);
   the anchor itself is the actual flex child, so it needs the sizing
   that used to sit directly on the img -- otherwise it defaults to a
   shrinkable flex item and the img's own flex:0 0 auto has no effect.
   It's given a fixed area (220x140) and centers whatever-shaped logo
   sits inside it, both horizontally and vertically. */
.page-sponsors section.sponsor-card > a{
  flex: 0 0 auto;
  display: flex;
  align-items: center;
  justify-content: center;
  width: 220px;
  height: 140px;
  max-width: 100%;
}
.page-sponsors section.sponsor-card .sponsor-logo{
  max-width: 100%;
  max-height: 100%;
  width: auto;
  height: auto;
  display: block;
  border-radius: 15px;
  box-shadow: 0 2px 10px rgba(0,0,0,0.25);
  margin: 0;
}
.page-sponsors section.sponsor-card p{
  flex: 1 1 auto;
  margin: 0;
}
/* Brockhaus specifically read as cramped (its card was the shortest of
   the five before this change) -- give its text extra breathing room
   above and below, roughly double the gap the other cards get simply
   from the row's own vertical centering */
.page-sponsors section#Brockhaus.sponsor-card p{
  padding: 1rem 0;
}
@media (max-width: 699px){
  .page-sponsors section.sponsor-card{
    flex-direction: column;
    min-height: 0;
  }
  .page-sponsors section.sponsor-card > a{
    margin: 0 auto 1rem;
  }
}
section.content-section h2{
  color: var(--t-heading, var(--navy));
  font-size: 1.5rem;
  border-left: 6px solid var(--t-accent, var(--green));
  padding-left: 0.6rem;
  margin: 0 0 0.9rem;
}
section.content-section h3{
  color: var(--t-subheading, var(--t-heading, var(--blue-btn-bot)));
  font-size: 1.1rem;
  margin: 1.2rem 0 0.5rem;
}
section.content-section p{ margin: 0 0 0.765rem; color: var(--t-text, #2c3540); }

/* Venue page: photo+text card pattern -- a photo sits beside a specific
   paragraph (or two photos flank one), while other paragraphs in the same
   card stay full-width. Falls back to a stacked column on narrow
   viewports so photos never get squeezed alongside long text. */


.page-venue .venue-photo-row{
  display: flex;
  align-items: center;
  gap: 2rem;
  margin-bottom: 0.765rem;
}
/* pairs a photo with just one (often long) paragraph within a card that
   otherwise has other, full-width paragraphs -- top-aligns the photo
   instead of centering it against the whole paragraph height, which
   would look odd once the text runs long */
.page-venue .venue-photo-row.align-top{
  align-items: flex-start;
}
.page-venue .venue-photo{
  flex: 0 0 auto;
  width: 280px;
  height: 180px;
  max-width: 100%;
  object-fit: cover;
  display: block;
  border-radius: 15px;
  box-shadow: 0 2px 10px rgba(0,0,0,0.25);
  margin: 0;
}
/* portrait variant for photos naturally taller than wide (e.g. the
   Leaning Tower) -- a landscape frame would crop away too much */
/* HOW MANY PHOTOGRAPHS THE CAROUSEL SHOWS DEPENDS ON THE SCREEN.

   Four side by side is right on a desktop. On a phone they reflow into a
   column nearly a thousand pixels tall - more than a whole screen of
   scrolling past a decoration, which sits oddly with the trouble taken to
   reclaim space at the top of every page.

   So: ONE in portrait, TWO in landscape, four otherwise. The extra slots
   are hidden rather than removed, so the count can change when the phone is
   turned without rebuilding anything. The script reads how many are actually
   visible rather than assuming, and redraws when that number changes. */
@media (max-width: 620px){
  .page-venue .tuscany-carousel img.tuscany-slot:nth-child(n+2){ display: none; }
}
@media (max-height: 500px) and (orientation: landscape){
  .page-venue .tuscany-carousel img.tuscany-slot:nth-child(n+3){ display: none; }
}

.page-venue .venue-photo.portrait{
  width: 200px;
  height: 310px;
}
/* near-square variant, used when two photos flank one paragraph */
.page-venue .venue-photo.square{
  width: 240px;
  height: 248px;
}
/* stacks two same-width photos vertically in the left column, e.g. to
   fill the empty space that a single portrait photo leaves alongside a
   much longer paragraph */
.page-venue .venue-photo-stack{
  flex: 0 0 auto;
  display: flex;
  flex-direction: column;
  gap: 1rem;
}
.page-venue .venue-photo-stack .venue-photo{
  margin: 0;
}
.page-venue .venue-photo-text{
  flex: 1 1 auto;
}
.page-venue .venue-photo-text p{
  margin: 0 0 0.765rem;
}
.page-venue .venue-photo-text p:last-child{
  margin-bottom: 0;
}
/* single-paragraph case: the <p> sits directly in the row instead of
   being wrapped in .venue-photo-text */
.page-venue .venue-photo-row > p{
  flex: 1 1 auto;
  margin: 0;
}
@media (max-width: 699px){
  .page-venue .venue-photo-row{
    flex-direction: column;
  }
  .page-venue .venue-photo{
    width: 100%;
    max-width: 280px;
    margin: 0 auto 1rem;
  }
  .page-venue .venue-photo.portrait{
    height: auto;
    max-width: 200px;
  }
  .page-venue .venue-photo.square{
    height: auto;
    max-width: 240px;
  }
  .page-venue .venue-photo-stack{
    flex-direction: column;
    align-items: center;
  }
}

/* HELD UPRIGHT, THE TWO PHOTOGRAPHS STACK BESIDE THE TEXT.

   Side by side they took 480px of a card barely 560px wide and left the
   paragraph a ribbon of text about 130px across. Putting them one above the
   other returns most of that width to the text while keeping the pairing -
   the text still reads beside its pictures rather than above them.

   Placed by grid rather than by source order: the markup is paragraph,
   photograph, photograph, which is the right reading order and the right
   arrangement on a wide screen; here the two photographs have to share a
   column. Rows with a single photograph are unaffected - the paragraph
   simply spans the one row that exists.

   Below 700px there is no width for two columns at all, so the older rule
   further down stacks everything instead. */
@media (orientation: portrait) and (min-width: 700px){
  .page-venue .venue-photo-row{
    display: grid;
    grid-template-columns: minmax(0, 1fr) auto;
    column-gap: 1.6rem;
    row-gap: 1rem;
    align-items: start;
  }
  .page-venue .venue-photo-row > p{ grid-column: 1; grid-row: 1 / span 2; }
  .page-venue .venue-photo-row > img:nth-of-type(1){ grid-column: 2; grid-row: 1; }
  .page-venue .venue-photo-row > img:nth-of-type(2){ grid-column: 2; grid-row: 2; }
}

/* Tourism carousel: 4 photos shown at once, centered, cross-fading
   between random sets drawn from a non-Pisa Tuscany pool (js/main.js) --
   a stationary fade rather than a sliding strip. */
.page-venue .tuscany-carousel{
  display: flex;
  justify-content: center;
  align-items: center;
  gap: 2.5rem;   /* matches the card's own top gap above the title */
  flex-wrap: wrap;
  margin-top: 1.5rem;
  margin-bottom: 1rem;   /* combined with the card's own bottom padding, matches the card's top gap above the title */
}
/* Tourism card specifically: 50% more spacing between paragraphs/photo-rows
   than the site default, since this card has unusually many consecutive
   blocks of text */
.page-venue #Attractions > p{
  margin-bottom: 1.8rem;
}
.page-venue #Attractions .venue-photo-row{
  margin-bottom: 1.8rem;
}
.page-venue .tuscany-carousel img.tuscany-slot{
  width: 268px;
  height: 176px;
  object-fit: cover;
  border-radius: 15px;
  box-shadow: 0 2px 10px rgba(0,0,0,0.25);
  opacity: 0;
  transition: opacity 0.9s ease;
}
/* FEWER PHOTOGRAPHS ON A PHONE.

   Four of them stacked into a 950px column in portrait - more than a whole
   screen of decoration to scroll past, on a page whose actual content sits
   below it. One is plenty when they are shown one above the other, and two
   fit comfortably side by side when the phone is held sideways.

   The script picks exactly as many as are shown (see lowerSlotCount in
   js/main.js), so the hidden ones are not merely invisible - they are never
   chosen, and never occupy a photograph the banner could have used. */
@media (max-width: 900px) and (orientation: landscape){
  .page-venue .tuscany-carousel img.tuscany-slot:nth-child(n+3){ display: none; }
}
@media (max-width: 900px) and (orientation: portrait){
  .page-venue .tuscany-carousel img.tuscany-slot:nth-child(n+2){ display: none; }
}

.page-venue .tuscany-carousel img.tuscany-slot.visible{
  opacity: 1;
}
@media (max-width: 699px){
  .page-venue .tuscany-carousel img.tuscany-slot{
    width: 100%;
    max-width: 340px;
    height: 210px;
  }
}
section.content-section ul{
  list-style: disc;
  margin: 0 0 1rem;
  padding-left: 1.4em;
  color: var(--t-text, #2c3540);
}
section.content-section li{ margin: 0 0 0.405rem; }
section.content-section li:last-child{ margin-bottom: 0; }

/* THE CONFERENCE TRACKS, on the Overview and the Papers page.

   Each track is a heading with its own points beneath it, as a nested list
   rather than as one run-on sentence: the points are separate ideas and read
   better separately, and an author scanning for their subject finds it
   faster.

   The inner list is set tight - single spacing, no gap between the points -
   so each track still reads as one block. Without this the shared rule above
   would put 0.405rem between every point and the four tracks would sprawl.

   A dash rather than a second bullet, so the two levels are told apart at a
   glance without indenting far enough to waste width on a phone. */
section.content-section ul.track-list > li{ margin-bottom: 0.9rem; }
section.content-section ul.track-list > li:last-child{ margin-bottom: 0; }

/* KEEP THE POINTS THE SAME SIZE AS THE TEXT AROUND THEM.

   The site sets list items to 1.15em, which is right for a single list - but
   em is RELATIVE, so a list inside a list multiplies it twice and the inner
   points came out 15% larger than the surrounding paragraphs (14.7 -> 16.9 ->
   19.5px). This puts the second level back to the size its parent already is.

   The selector is this long on purpose: the rule it has to override is
   written per page ('.page-papers section.content-section li' and so on), so
   a shorter selector here would simply lose and the points would stay big. */
section.content-section ul.track-list ul > li{ font-size: 1em; }

section.content-section ul.track-list ul{
  list-style: none;
  margin: 0.2rem 0 0;
  padding-left: 1.1em;
}
section.content-section ul.track-list ul > li{
  margin: 0;                 /* single spacing between the points */
  text-indent: -1.1em;       /* wrapped lines line up under the first word, */
  padding-left: 1.1em;       /* not under the dash */
}
section.content-section ul.track-list ul > li::before{
  content: "\2013\00a0";    /* en dash + a non-breaking space */
  color: var(--t-text, #2c3540);
}
/* the paragraph right before a list gets the same trailing gap as the
   list's own items, instead of the (larger) normal paragraph spacing */
section.content-section p:has(+ ul){ margin-bottom: 0.405rem; }
section.content-section a{
  color: var(--t-subheading, var(--t-heading, var(--blue-btn-bot)));
  text-decoration: underline;
  text-underline-offset: 2px;
  font-weight: 600;
}

/* explicit bright-blue highlight for hand-picked keywords/links */
.hl-blue{ color: #0000cc; }
section.content-section a.hl-blue{ color: #0000cc; }
section.content-section a:hover{ opacity: 0.75; }

/* Venue page: larger, Tahoma-style body copy (per later refinement) */
.page-welcome section.content-section p,
.page-welcome section.content-section li,
.page-welcome .hero p.lead,
.page-welcome table.info-table,
.page-side-events section.content-section p,
.page-side-events section.content-section li,
.page-side-events .hero p.lead,
.page-side-events table.info-table,
.page-venue section.content-section p,
.page-venue section.content-section li,
.page-venue .hero p.lead,
.page-venue table.info-table,
.page-registration section.content-section p,
.page-registration section.content-section li,
.page-registration .hero p.lead,
.page-registration table.info-table,
.page-papers section.content-section p,
.page-proceedings section.content-section p,
.page-papers section.content-section li,
.page-proceedings section.content-section li,
.page-papers .hero p.lead,
.page-proceedings .hero p.lead,
.page-program section.content-section p,
.page-program section.content-section li,
.page-program .hero p.lead,
.page-sponsors section.content-section p,
.page-sponsors section.content-section li,
.page-sponsors .hero p.lead,
.page-news section.content-section p,
.page-news section.content-section li,
.page-news .hero p.lead,
.page-proceedings table.info-table,
.page-program table.info-table{
  font-family: var(--font-nav);
  font-size: 1.15em;
}
/* Committee tables (Welcome page): every name bold, and the Name column
   (plus Track, in the Technical Committee table) held to a fixed width so
   the Country column lines up at the same horizontal position in every
   table on the page, regardless of the longest name in that particular
   committee */
.page-welcome table.info-table td:first-child,
.page-welcome table.info-table th:first-child{
  font-weight: 700;
}
.page-welcome table.info-table td:first-child{
  color: #8a1414;   /* the dark red presently used for the table header */
}
.page-welcome table.info-table td:nth-child(2),
.page-welcome table.info-table th:nth-child(2){
  text-align: center;   /* country code centred beneath "Country" -- header needs the same alignment or the two visually mismatch */
}
.page-welcome table.info-table th{
  font-style: italic;
  color: #000000;
  background: ivory;
}
.page-welcome table.info-table td{
  background: ivory;
}
.page-welcome table.info-table td,
.page-welcome table.info-table th{
  line-height: 0.992;   /* a further -20% from 1.24 */
}
/* Track column of the Technical Program Committee table (#Technical) — the
   only cell in any of these tables long enough to wrap. At the shared
   0.992 its wrapped lines sat too tight, so it gets its own value: 1.24,
   which is exactly 80% of the site's in-paragraph line-height (1.55).
   (That's also where the shared value started before it was cut a further
   20% — so this column simply opts out of that last reduction.)
   td only, not th: the "Track" header never wraps, and including it would
   just make the header row taller for nothing. Deliberately outside the
   width media queries, since the wrapping happens at every width. */
#Technical table.info-table td:nth-child(3){
  line-height: 1.24;
}
.page-welcome table.info-table{
  margin-bottom: 1rem;   /* matches the free space below a normal paragraph (section.content-section p) */
}
@media (max-width: 699px){
  .page-welcome table.info-table{
    table-layout: fixed;   /* without this, a single long word (e.g. in Track) can force the table wider than its container */
  }
  .page-welcome table.info-table td,
  .page-welcome table.info-table th{
    word-break: break-word;
    padding: 0.5em 0.4em;
  }
  .page-welcome table.info-table th:first-child,
  .page-welcome table.info-table td:first-child{
    width: 34%;
  }
  .page-welcome table.info-table th:nth-child(2),
  .page-welcome table.info-table td:nth-child(2){
    width: 18%;
  }
  .page-welcome table.info-table th:nth-child(3),
  .page-welcome table.info-table td:nth-child(3){
    width: 48%;
  }
}
@media (min-width: 700px){
  .page-welcome table.info-table{
    width: auto;   /* override the site-wide width:100%, so table-layout:fixed sizes each table from its own column widths instead of stretching them to fill the container */
    /* NOTE: no explicit table width here any more -- with table-layout:fixed,
       forcing a shared width on a 2-column table proportionally stretches
       its columns to fill that width, which fights the fixed Country
       width below (8em stops being 8em). Letting each table size itself
       from its own column widths keeps Name/Country genuinely consistent
       across every table; the 3-column table (Name+Country+Track=54em)
       still ends up the widest, 2-column tables are correspondingly
       narrower rather than padded with empty trailing space. */
    table-layout: fixed;   /* respect the explicit column widths below precisely, instead of auto-redistributing leftover space into Name */
  }
  .page-welcome table.info-table th:first-child,
  .page-welcome table.info-table td:first-child{
    /* 16em, not the 15 it was. "Antonio J. Marques Cardoso" is the longest
       name in any of these committees and needs 262px including the cell's
       own padding - 15.48em at this size - so at 15em it wrapped onto a
       second line and made that one row of the Publicity table taller than
       the rest.

       Widened here rather than on that one table, because the whole point of
       a fixed Name column is that the Country column starts at the same place
       in every committee; a table with a wider Name column would break the
       alignment down the page. 16em leaves about half a character of slack,
       enough that a slightly wider name would not need this revisiting. */
    width: 16em;
  }
  .page-welcome table.info-table th:nth-child(2),
  .page-welcome table.info-table td:nth-child(2){
    width: 8em;   /* same narrow width in every table, so the centred country code sits right after the Name column consistently */
  }
  /* NOTE: there used to be a `#TechnicalCommittee ... :nth-child(3){ width: 31em }`
     rule here, meant to keep each Track entry on a single line. It went dead when
     the section was renamed to id="Technical" and was removed in the cleanup pass:
     the wrapped layout it had stopped producing is the one that's actually wanted,
     with the Track column's own line-height set above. Don't re-add it. */
}
/* Venue content runs noticeably wider than the site default (130%), and
   the hero lead's separate character-count cap is dropped so every piece
   of text on the page shares the same right-hand boundary */
.page-welcome .page-main-inner,
.page-side-events .page-main-inner,
.page-venue .page-main-inner,
.page-registration .page-main-inner,
.page-papers .page-main-inner,
.page-program .page-main-inner,
.page-sponsors .page-main-inner,
.page-proceedings .page-main-inner{ max-width: 1550px;   /* -8% from 1685px */ }   /* +20% from 1404px */
.page-news .page-main-inner{ max-width: 1550px;   /* -8% from 1685px */ }   /* +20% from 1404px */
/* Venue's content rarely reaches that max-width, so once the browser is
   shrunk down from full-size (but still well above phone width), the
   left/right margins were only the site-wide 1.5rem -- barely noticeable
   on a wide window. Triple them for that "shrunk browser" range; true
   mobile keeps the normal, already-adequate margin. */
@media (min-width: 561px){
  .page-welcome .page-main-inner,
  .page-side-events .page-main-inner,
  .page-venue .page-main-inner,
  .page-registration .page-main-inner,
  .page-papers .page-main-inner,
  .page-program .page-main-inner,
  .page-sponsors .page-main-inner,
  .page-proceedings .page-main-inner{ padding-left: 4.5rem; padding-right: 4.5rem; }
  .page-news .page-main-inner{ padding-left: 4.5rem; padding-right: 4.5rem; }
}
.page-welcome .hero p.lead,
.page-side-events .hero p.lead,
.page-venue .hero p.lead,
.page-registration .hero p.lead,
.page-papers .hero p.lead,
.page-proceedings .hero p.lead,
.page-program .hero p.lead,
.page-sponsors .hero p.lead{ max-width: none; }
.page-news .hero p.lead{ max-width: none; }
/* Venue sub-titles (City, Connections, etc.): bigger, brighter red, 3D effect */
/* ---------- Title style: badge look, shared by Welcome, Side Events, Venue ---------- */
.page-welcome section.content-section h2,
.page-side-events section.content-section h2,
.page-venue section.content-section h2,
.page-registration section.content-section h2,
.page-papers section.content-section h2,
.page-proceedings section.content-section h2,
.page-program section.content-section h2{
  display: inline-block;
  font-family: var(--font-display);   /* shipped with the site */
  font-weight: var(--heading-weight);
  font-style: italic;
  font-size: calc(1.368rem * var(--heading-scale));   /* base was 1.71rem, -20% */
  letter-spacing: 1px;
  color: var(--yellow-badge);
  background: linear-gradient(180deg, #3a67d1 0%, #294ab7 55%, #253692 100%);   /* lightened badge blue, shifted toward the vivid link blue */
  border-left: none;
  border-radius: 10px;
  padding: 0.1875em 1.0124em;   /* horizontal +25%, +20%, then +20% again */
  margin: 1.296rem 0 2.025rem;   /* top -20% again (was 1.62rem); bottom unchanged */
  box-shadow:
    inset 0 1px 0 rgba(255,255,255,0.25),
    inset 0 -2px 4px rgba(0,0,0,0.3),
    0 4px 0 var(--blue-btn-bot),
    0 7px 12px rgba(0,0,0,0.35);
  text-shadow: 1px 1px 0 rgba(0,0,0,0.4), 2px 2px 3px rgba(0,0,0,0.3);
}
/* Now that the badge sits inside a padded card (site-wide), rebalance so
   the total gap above it (card's own 1.5rem top padding + this) equals
   the badge's own margin-bottom (2.025rem) below it */
.page-welcome section.content-section h2,
.page-venue section.content-section h2,
.page-papers section.content-section h2,
.page-proceedings section.content-section h2,
.page-program section.content-section h2,
.page-registration section.content-section h2,
.page-side-events section.content-section h2,
.page-sponsors section.content-section h2{
  margin-top: 0.525rem;
}
.page-welcome .hero h1,
.page-side-events .hero h1,
.page-venue .hero h1,
.page-registration .hero h1,
.page-papers .hero h1,
.page-proceedings .hero h1,
.page-program .hero h1,
.page-sponsors .hero h1,
.page-news .hero h1{
  display: inline-block;
  font-family: var(--font-display);   /* shipped with the site */
  font-weight: var(--heading-weight);
  font-size: calc(1.62rem * var(--heading-scale));   /* base was 1.8rem, -10% */
  font-style: italic;   /* the page title, matching the workshop name in the
                           banner above it and the section badges below */
  letter-spacing: 0.6px;   /* slightly reduced, title only */
  color: var(--yellow-badge);
  background: linear-gradient(180deg, #b31f1f 0%, #8a1414 55%, #6b0f0f 100%);   /* dark red, same one used on the Overview page, replacing the blue */
  border-radius: 12px;
  padding: 0.135em 0.7087em;   /* vertical unchanged; horizontal -10%, +25%, then +20% */
  /* THE SPACE ABOVE THE BADGE IS 125% OF THE SPACE BELOW IT.

     Above is this top margin PLUS the block's own top padding; below is the
     bottom margin alone, up to the first line of text. So the two are not
     simply the two margins, and the top figure is set from the measured
     result rather than by halving anything. */
  /* THE SPACE ABOVE THE BADGE IS 125% OF THE SPACE BELOW IT.

     It used to be nearer 235%: the badge sat a long way under the bar above
     and close to the text it introduces, so it read as belonging to neither.
     The top margin is now zero - the space above is what the page's own top
     padding provides - and the bottom margin carries the balance.

     Measured, not calculated: the space above is the top margin PLUS the
     block's own top padding and the line box around it, so the two figures
     are not simply the two margins. */
  margin: 0 0 2.091rem;
  box-shadow:
    inset 0 1px 0 rgba(255,255,255,0.25),
    inset 0 -2px 4px rgba(0,0,0,0.3),
    0 5px 0 #6b0f0f,
    0 9px 16px rgba(0,0,0,0.4);
  text-shadow: 1px 1px 0 rgba(0,0,0,0.4), 2px 2px 3px rgba(0,0,0,0.3);
}
/* highlighted keywords/links use a slightly darker red than the base
   .hl-red default, freeing up bright blue exclusively for ordinary
   content links and the separate .hl-blue highlight, on all pages */
.page-welcome .hl-red, .page-side-events .hl-red, .page-venue .hl-red, .page-registration .hl-red, .page-papers .hl-red, .page-program .hl-red, .page-sponsors .hl-red, .page-news .hl-red, .page-proceedings .hl-red{ color: #a81c1c; }
.page-welcome section.content-section a.hl-red,
.page-side-events section.content-section a.hl-red,
.page-venue section.content-section a.hl-red,
.page-registration section.content-section a.hl-red,
.page-papers section.content-section a.hl-red,
.page-proceedings section.content-section a.hl-red,
.page-program section.content-section a.hl-red,
.page-sponsors section.content-section a.hl-red,
.page-news section.content-section a.hl-red{ color: #a81c1c; }
.page-welcome section.content-section a,
.page-side-events section.content-section a,
.page-venue section.content-section a,
.page-registration section.content-section a,
.page-papers section.content-section a,
.page-proceedings section.content-section a,
.page-program section.content-section a,
.page-sponsors section.content-section a,
.page-news section.content-section a,
.page-welcome .hero a,
.page-side-events .hero a,
.page-venue .hero a,
.page-registration .hero a,
.page-papers .hero a,
.page-proceedings .hero a,
.page-program .hero a,
.page-sponsors .hero a,
.page-news .hero a{ color: #0000cc; }
section.content-section p a{
  color: var(--t-subheading, var(--t-accent, var(--blue-btn-bot)));
  font-weight: 600;
  text-decoration: underline;
  text-decoration-color: currentColor;
  text-underline-offset: 2px;
}
section.content-section p a:hover,
section.content-section p a:focus-visible{
  text-decoration-thickness: 2px;
}

table.info-table{
  width:100%;
  border-collapse: collapse;
  margin-top: 0.5rem;
  font-size: 0.95rem;
  color: var(--t-text, #2c3540);
}
table.info-table th, table.info-table td{
  text-align:left;
  padding: 0.6em 0.8em;
  border-bottom: 1px solid var(--t-rule, var(--rule));
}
table.info-table th{
  background: var(--t-card-bg, #eef2f6);
  color: var(--t-heading, var(--navy));
  font-family: var(--font-nav);
}

.news-list{ display:flex; flex-direction:column; gap: 1rem; }
.news-list article{
  background: ivory;
  border-left: 6px solid #8a1414;
  border-radius: 15px;   /* matches the site-wide card corner radius */
  padding: 1.975rem 2.5rem 1.5rem;   /* matches the site-wide card padding */
  color: var(--t-text, #2c3540);
}
section.content-section .news-list h3{
  font-family: var(--font-nav);
  font-size: 1.15em;
  color: var(--t-heading, var(--navy));
  margin: 0 0 0.5em;
}
.news-list time{
  display:block;
  font-family: var(--font-util);
  font-size: 1.12rem;   /* +40% from 0.8rem */
  color: var(--t-lead, #8a8f96);
  margin-bottom: 0.25em;
}

/* =========================================================
   PAGE BACKGROUND THEME
   =========================================================
   All 8 pages carry `class="theme-photo-tile-raw"` on <main>; this rule
   supplies the repeating background tile plus the --t-* custom properties
   (text/heading/card colours) that the rest of the stylesheet reads via
   var(--t-*, fallback).

   HISTORY: this section once held ~11 alternative .theme-* variants
   (ivory / vellum / papyrus / kraft / grey / darkred / darkgreen / facet /
   ion / ribbon / photo-tile) built to sample different looks side by side.
   The choice was settled on the one below and the rest were removed in the
   cleanup pass, along with four texture-*.png files they referenced that
   had never been shipped in images/. If another look is ever wanted, add a
   single new .theme-* class here defining the same --t-* set and swap the
   class on <main> — don't reintroduce the whole gallery.

   The live --t-* contract is exactly: --t-bg, --t-text, --t-heading,
   --t-subheading, --t-lead, --t-card-bg, --t-rule, --t-accent. (A
   --t-card-border was also defined here until the cleanup pass, but its
   only consumers were the unused .card / form.dummy-form rules, so it was
   dropped with them.)
   ========================================================= */
/* The user's original photo, unmodified in colour/contrast — only made
   seamlessly repeatable. (Named "-raw" to distinguish it from an earlier,
   colour-adjusted variant that was dropped; first trialled on Registration
   alone, now used by every page.) */
.theme-photo-tile-raw{
  background-image: url("../images/BackgroundTexture.png");
  background-repeat: repeat;
  --t-bg: #f6ecc8;
  --t-text: #17140f;
  --t-heading: #8a1414;
  --t-subheading: #1c4f91;
  --t-lead: #17140f;
  --t-card-bg: rgba(255,255,255,0.6);
  --t-rule: #e3d6a8;
  --t-accent: #8a1414;
}

/* =========================================================
   Bottom — permanent single line, pinned to the viewport bottom
   ========================================================= */
.band-bottom{
  position: sticky;
  bottom: 0;
  z-index: 90;
  flex: 0 0 auto;
  background: var(--navy-deep);
  color: var(--grey-light);
  font-family: var(--font-util);
  font-size: 0.8rem;
  /* UNEVEN ON PURPOSE, and centred on the BODY OF THE LOWERCASE - the band
     between the x-height line and the baseline - not on the full extent of
     the ink. Capitals and ascenders reach well above that body and only the
     descenders fall below it, so centring the ink as a whole leaves the part
     the eye actually reads sitting high.

     THE BAND IS ALSO DEEPER THAN IT WAS, ~31.5px against ~27px. The old
     figure was chosen to be as shallow as possible and looked cramped on a
     desktop.

     MEASURED FROM THE TOP OF THE NAVY, NOT FROM THE TOP OF THE BOX. The band
     carries a 1px border along its top edge, a hair lighter than the navy
     below it. Counting that border as part of the band, the line was centred;
     but the eye reads it as the edge of the band rather than as part of it,
     so what is actually seen is 1px less space above the words than the
     measurement claimed - and the line looked high. Twice.

     So the reference is the first row of navy, and these two figures are
     SOLVED rather than sampled. Reading the position off a screenshot means
     reading a rasterised image, and the answer then depends on the device
     pixel ratio - the same page measured at 6x and at 8x gave 12.67 and
     12.50. Computed instead from the box model and the font's own metrics -
     border, padding, line box, and where the x-height sits inside it - the
     body of the lowercase has 12.078px above it and 12.078px below. Exactly
     centred, and the same number on any screen.

     The band is 32.16px, a little deeper than the 31.5 it was: the height had
     to give slightly for the two to come out equal. */
  padding: 0.337rem 1.5rem 0.541rem;
  text-align:center;
  border-top: 1px solid rgba(255,255,255,0.08);
}
.band-bottom p{ margin:0; }
.band-bottom a{ color: var(--cyan); text-decoration:none; }
.band-bottom a:hover{ text-decoration:underline; }

/* THE FOOTER SAYS LESS ON A SMALL SCREEN.

   The full line runs to three wrapped rows on a phone - most of it the
   workshop's formal name, which is already at the top of every page - so a
   shortened version is used instead and the band is a quarter shallower. */
.foot-compact{ display: none; }
@media (max-width: 1024px){
  .foot-full{ display: none; }
  .foot-compact{ display: block; }
  /* No padding of its own any more: the base rule now gives every mode the
     same footer height, which used to differ - 40px on a desktop, 30 in
     landscape, 27 in portrait. The portrait figure was the one to keep. */
  .band-bottom{ min-height: 0; }
}

/* Narrower than about 380px the shortened line still runs onto a second row,
   which puts the height straight back. The wording cannot shrink further
   without losing something worth keeping, so the type does instead - one
   step, enough to hold it on a single line down to 320px. */
@media (max-width: 560px){
  .band-bottom{
    font-size: 0.66rem;
    /* More padding than the base rule, because the type is smaller and the
       aim is the SAME footer depth in every mode.

       Centred on the same thing - the body of the lowercase.

       CENTRED EXACTLY, like the base rule, and by the same method: computed
       from the box model rather than sampled from a screenshot. 12.141px
       above the body of the lowercase and 12.141px below.

       THE BAND IS 31.28px HERE AGAINST 32.16px ELSEWHERE. The two were made
       equal once, which cost a fraction of a pixel of centring; exact
       centring at two different type sizes needs two slightly different
       heights, and 0.9px of depth is not visible while a line sitting off
       centre is. The two are never seen side by side in any case. */
    padding-top: 0.483rem;
    padding-bottom: 0.551rem;
  }
}

/* The visit counter, drawn by the site itself rather than fetched as an
   image from elsewhere. Styled to sit quietly at the end of the footer line,
   in the same navy as the band it sits on. */
.hit-counter{
  /* Positioned rather than in the flow, as the image it replaces was: the
     footer text wraps to two or three lines and the badge sits clear of it
     at the right-hand end. */
  position: absolute;
  right: 1.25rem;
  top: 50%;
  transform: translateY(-50%);
  display: inline-flex;
  align-items: stretch;
  border-radius: 4px;
  overflow: hidden;
  font-family: var(--font-util);
  font-size: 0.78em;
  line-height: 1;
  white-space: nowrap;
}
.hit-counter-label{
  background: #4a5058;
  color: #fff;
  padding: 0.34em 0.5em;
}
.hit-counter-value{
  background: var(--navy-deep, #0a3672);
  color: #fff;
  font-weight: 700;
  font-variant-numeric: tabular-nums;   /* the width will not jitter as it rises */
  padding: 0.34em 0.5em;
}

@media (max-width: 640px){
  /* THE COUNTER IS SHOWN ON A PHONE TOO, now that both it and the footer
     line have been shortened: "Visits" rather than "Total visits", and the
     short form of the credit line. Measured at 390px there are 346px of room
     and the two together need 332.

     Below 390px it goes: at 360 they are 16px too wide and at 320 they are
     56px too wide, and a counter overlapping the credit line is worse than
     no counter at all. */
  .hit-counter{ display: inline-flex; }
}
/* The credit line is centred in the WHOLE width, so where a counter shares
   the row its right end ran underneath it. Reserving the counter's space
   means the line centres in what is left. ONLY where the counter is
   actually shown: applied below 390px as well it pushed the line onto two
   rows and put back the height the shortening had just saved. */
@media (min-width: 390px) and (max-width: 560px){
  .foot-compact{ padding-right: 4.4rem; }
}

@media (max-width: 389px){
  .hit-counter{ display: none; }
}

/* =========================================================
   NO FOOTER ON A PHONE HELD SIDEWAYS
   =========================================================
   Turned sideways a phone has about 390px of height, and the fixed bands -
   title, ribbon, buttons or news, and footer - were taking roughly half of
   it. The page itself got what was left, which made reading anything a
   chore.

   The footer is the one that can go. Its credit line repeats the workshop's
   full name, which is in the band at the top of the very same screen, and
   the copyright. What it holds that is NOT repeated is the webmaster's
   address and the visit counter, so those two move up into the title band,
   pinned to its right-hand end: the address as a bare "@", which is enough
   to be recognised as a mail link and costs almost no width.

   Scoped by HEIGHT, not width. A tablet held sideways is around 960px tall
   and has room to spare; a phone is under 500 whichever way its width falls.
   ========================================================= */
.title-utils{ display: none; }

/* The rules for this case are further down, after the landscape blocks they
   have to override - search for A PHONE HELD SIDEWAYS. */


/* =========================================================
   RESPONSIVE
   ========================================================= */
@media (max-width: 900px){
  :root{
    /* 2.94rem, not 3: on a phone held sideways the title nearly touched
       the logos either side - the space between them came to only about one
       word-gap, which read as cramped. At this size it is about one and a
       half, matching the proportion used elsewhere.

       The relationship is not a simple one: the logos are drawn at 1.5x the
       title's size, so shrinking the title also shrinks them and widens the
       space twice over. The figure was found by measuring, and the ratio
       changes quickly either side of it. */
    --fs-acronym: 2.94rem;
    --fs-fullname: 1.26rem;   /* the same -10% on small screens */
  }
  .band-ribbon-inner{ gap:1rem; }
}

/* ---------------------------------------------------------------------------
   THE LOGOS SIT BESIDE THE TITLE, NOT AT THE EDGES OF THE SCREEN
   ---------------------------------------------------------------------------
   They used to be pushed apart to the two ends of the band, with the title
   stretched to fill whatever was left. On a wide monitor that made the
   acronym enormous - 964px across at 1600 - while the space between it and
   each logo stayed at about 22px. The band read as three things shoved to
   the edges rather than as one title with its two marks either side.

   Now the three are grouped and the group is centred, with a FIXED distance
   between each logo and the title. Extra width goes to the OUTSIDE, where it
   is simply margin, instead of being poured into the lettering.

   The figure is taken from the arrangement the user showed: 67px on one side
   and 71px on the other, against a title 810px wide. 4.55rem is 67px at the
   root size, and stays proportional if that ever changes.

   ALL LANDSCAPE WIDTHS, with the gap scaling below the ceiling so that
   narrowing the window shrinks the whole group together rather than stepping
   between arrangements. Held upright both phone and tablet have their own
   layouts further down and neither wants this one. */
@media (orientation: landscape){
  .band-ribbon-inner{
    justify-content: center;
    /* THE GAP SCALES WITH THE WINDOW, up to a ceiling. A fixed 4.1rem was
       right on a wide monitor and far too greedy on a narrow one, where it
       took room out of the lettering; and being scoped to 1280px and up it
       put a cliff in the middle of the range - one pixel narrower and the
       logos jumped back to the two ends of the band.

       min() removes the cliff: 5.3vw below about 1140px, the 4.1rem ceiling
       above it. Nothing here reads the title's size, so there is no loop
       between the two. */
    /* A FIFTH MORE THAN THE 4.1rem/5.3vw first set. With the marks at 1.35x
       instead of 1.5 there is width to spend, and it goes here: the group
       reads as a title with two marks beside it rather than three things
       filling the band. */
    gap: min(4.92rem, 6.36vw);
  }
  /* The title block must stop growing, or it eats the room the centring is
     meant to leave: it takes the width its own lettering needs and no more.
     The `1` in the middle is kept so it can still SHRINK on a narrow window,
     which is what the fit-to-width script relies on. */
  .ribbon-left{ flex: 0 1 auto; }
}

/* THE MENU COLLAPSES AT 1024px, NOT 900px.

   The eight buttons plus their gaps need about 985px. The breakpoint used to
   be 900px, so on any window between roughly 910 and 930px the full bar was
   shown without room for it and the page gained a horizontal scrollbar -
   measured at up to 14px of overflow in two engines. Collapsing to the
   compact menu a little earlier removes that, and leaves enough headroom for
   the slightly larger button text.

   IF THE BUTTONS ARE EVER ENLARGED AGAIN, check this figure: the full bar
   must fit inside the narrowest window that still shows it. */
@media (max-width: 1024px){
  /* The hamburger used to be shown here. It is not shown anywhere any more -
     the "Menu" button in the news ribbon replaced it - and the rule that
     hides it is its own base rule near the top of this file. */
  .nav-inner{ justify-content:space-between; }
  .nav-buttons{
    display:none;
    flex-direction:column;
    position:absolute;
    top: 100%; left:0; right:0;
    background: var(--navy-deep);
    padding: 0.8rem;
    box-shadow: 0 10px 20px rgba(0,0,0,0.3);
  }
  .nav-buttons.open{ display:flex; }
  .nav-item{ width:100%; }
  .dropdown{
    position:static;
    transform:none !important;
    opacity:1; visibility:visible; pointer-events:auto;
    display:none;
    box-shadow:none;
    border: 1px solid rgba(255,255,255,0.25);
    margin-top: 0.4rem;
  }
  .dropdown::before{ display:none; }
  .nav-item.open .dropdown{ display:block; }
}

/* TURNED SIDEWAYS, ALL EIGHT BUTTONS ARE SHOWN - NO MENU AT ALL.

   A phone in landscape has width to spare and very little height, which is
   the opposite of what a drop-down menu is for. The row did not fit because
   of the space AROUND the words rather than the words themselves: with the
   side padding and the gaps squeezed, all eight fit at 844px at their full
   size, with nothing shrunk.

   And it is CHEAPER in height than the menu it replaces - about 45px against
   the 59px the hamburger's band was taking - so the page below gains as
   well.

   Below 820px there is no longer room for that, and the compact menu takes
   over again, laid out in two columns further down. */
@media (min-width: 820px) and (max-width: 1024px) and (orientation: landscape){
  /* the whole row is shown here, so the compact menu's control is not wanted -
     and the band gets its height back, having been collapsed by the rule
     above */
  .menu-button{ display: none; }
  .news-label{ display: inline; }   /* the word comes back with the full row */
  .band-buttons{
    /* Uneven on purpose, as on a desktop: the buttons carry a solid shadow
       along their lower edge which the eye counts as part of the button, so
       the space below has to be about 4px larger to look the same. */
    padding-top: 0.63rem;
    padding-bottom: 0.35rem;
  }
  .nav-inner{ justify-content: center; }
  .nav-buttons{
    display: flex;
    flex-direction: row;
    position: static;
    background: transparent;
    padding: 0;
    box-shadow: none;
    gap: 0.45rem;
    justify-content: center;
  }
  .nav-item{ width: auto; }
  .nav-btn{
    padding-left: 0.35em;
    padding-right: 0.35em;
    /* shorter than on a desktop: every pixel of the fixed top matters more
       when the screen is only 390px tall */
    /* vertical padding comes from the base rule, so a button is the same
       size here as in the Menu and on a desktop */
  }
  /* The dropdowns hang under their own button, as on a desktop.

     Written as `.nav-item .dropdown` this had no effect at all: the rule it
     has to beat is `.nav-item.open .dropdown`, which is more specific, so it
     won however late it appeared - the lists were still being placed for the
     compact menu and ended up 70px off the right of the screen. The
     transform needs !important for the same reason: the mobile block clears
     it with one. */
  .nav-item.open .dropdown{
    display: block;
    position: absolute;
    left: 50%;
    transform: translateX(-50%) !important;
    top: calc(100% + 8px);
    width: max-content;
    max-width: min(20rem, 92vw);
  }
}

/* TURNED SIDEWAYS, THE BUTTONS STAND IN TWO COLUMNS.

   A single column of eight was taller than the screen itself - 422px of menu
   on a 390px phone - so half the sections sat below the bottom edge. Two
   columns halve that, and the room they leave to the right is where the
   section lists open. It is the one arrangement that suits landscape rather
   than merely tolerating it: plenty of width, almost no height. */
@media (max-width: 1024px) and (orientation: landscape){
  .nav-buttons.open{
    display: grid;
    grid-template-columns: max-content max-content;
    /* The gaps are NOT set here. They come from the max-width:1024px rule
       that shows the "Menu" button, which uses one figure - 1.15rem - for the
       space between the buttons and for the margin round them. This rule used
       to set 0.9rem across and 0.3rem down, which left the panel with gaps
       that disagreed with its own padding, and the arithmetic that sizes it
       came out wrong in this one mode. */
    justify-content: start;
    align-content: start;
  }
  .nav-item{ width: auto; }
}


  @media (max-width: 900px) and (orientation: portrait){
    /* THE BAND THAT HELD THE BUTTONS IS EMPTY HERE, so it collapses - but that
       is done once for every compact-menu width, in the max-width:1024px block
       near the top of this file, and NOT repeated here. The landscape rule that
       gives the band its height back is scoped to landscape, so nothing between
       the two undoes it in portrait. */

    /* THE RIBBON IS A TENTH SHALLOWER HERE, and the word "Menu" is given the
       same space either side as it has above and below, so it sits in an even
       margin rather than in a tall narrow slot.

       These have to come AFTER the base rules they override: a media query
       adds no weight of its own, so with equal specificity it is source order
       that decides. Written earlier in the file, the ribbon simply kept its
       original height and nothing appeared to happen. */

    /* THE PANEL OPENS BELOW THE NEWS RIBBON, not over it.

       It is positioned under the band of buttons, which is where the ribbon
       now lives - so it covered the very button that opened it, and a second
       tap could not close the menu again. Pushing it down by the ribbon's
       height, and letting the ribbon paint over the panel, puts it where a
       reader expects: directly under the control they pressed.

       The height comes from the page itself (js/main.js keeps --news-h up to
       date) because it changes with the text size and the screen. */
    .band-news-row{ position: relative; z-index: 41; }
    .nav-buttons{ top: calc(100% + var(--news-h, 42px)); }
  }

  /* THE SAME OFFSET UP TO 1024px, NOT ONLY TO 900.

     The rule above lives in a max-width:900px block. Between 901 and 1024 in
     portrait the compact menu is still used but the offset was not applied,
     so the panel opened at top:100% - straight over the news ribbon and over
     the "Menu" button itself. The button was still there, underneath: it
     could not be pressed to close the menu, and a tap aimed at it hit the
     first button of the panel instead. A tablet held upright is exactly this
     range.

     Written as its own block rather than by widening the one above, which
     carries a good deal else that is meant for phones only. */
  @media (orientation: portrait) and (max-width: 1024px){
    .band-news-row{ position: relative; z-index: 41; }
    .nav-buttons{ top: calc(100% + var(--news-h, 42px)); }
  }


  /* THIS IS THE ARRANGEMENT FOR ANY SCREEN HELD UPRIGHT, not only a phone.

     Capped at 640px it left tablets out, and a tablet in portrait therefore
     used the wide arrangement - one logo either side of the title - which does
     not suit a tall narrow screen: the logos took the width, the title was
     fitted to what was left and came out far smaller than it needed to be,
     with 80px of its own column unused. */
  /* A TABLET HELD UPRIGHT HAS ROOM FOR A LARGER TITLE. The size below is a
     ceiling, not a fixed value - the fitting routine reduces it to whatever
     the column allows - but the ceiling was the one meant for a phone held
     sideways, so on a tablet the title stopped growing with 230px of its own
     column still empty. */


  /* A TABLET HELD UPRIGHT keeps the wide arrangement - a logo either side -
     but with smaller logos and a larger title.

     At 1.5x the title the logos were 95px tall on a 1200px screen: they took
     the width the title needed, and since the title and date are aligned to
     the top and bottom of the logos, the two lines were pushed 27px apart to
     span them. Both complaints - a small title and lines too far apart - come
     from that one figure.

     The title's own ceiling is raised at the same time, so it can use the
     width the smaller logos give back. It is a ceiling: the fitting routine
     still reduces it to whatever actually fits. */
  @media (orientation: portrait) and (min-width: 641px){
    :root{
      /* A SIZE OF THEIR OWN, not one derived from the title - see the note in
         syncTopLogos. Smaller than they were, which gives the title back the
         width it needs and brings the two lines closer, since they are aligned
         to the top and bottom of the logos. */
      --logo-fixed: 4.20rem;
      --fs-acronym: 5.2rem;
      /* A last trim applied AFTER the line has been fitted to the width - see
         fitOneLine. Both lines are limited by the room available here, so a
         smaller size asked for in the stylesheet would have no effect at all:
         the fit would simply shrink less and land in the same place. */
      --acronym-trim: 0.95;
      --dateloc-trim: 0.90;
    }
    /* The two lines are simply spaced here, rather than stretched to match the
       logos: that alignment belongs to the wide screen where the logos are
       drawn from the title. */
    .band-ribbon-inner{ padding: 1.000rem 2rem 1.500rem 2rem; }
    .ribbon-left{ row-gap: 0; }
    /* A NEGATIVE MARGIN, not a smaller gap: `row-gap` cannot go below zero, so
       once it was at zero the two lines were still 43px apart - most of that
       being the leading around a title this large, which the gap cannot touch.
       Pulling the date up with a margin can. */
    .ribbon-left .dateloc{ margin-top: -1.086rem; }
  }

  /* NARROW SCREENS HELD UPRIGHT - phones, in practice.

     Extending this to tablets was tried and looked worse: with the width for
     logos either side, the wide arrangement reads better than a stacked column
     with a very large title. The tablet keeps the wide one; what it needed was
     a bigger title and less distance between the two lines, and those are
     handled where that layout is defined. */
  @media (orientation: portrait) and (max-width: 640px){
    /* HELD UPRIGHT, THE TWO LOGOS STACK ON THE LEFT and the title sits beside
       them, rather than all three stacking in a column.

       A column put the workshop's name between the two logos and made the band
       the tallest thing on the screen. Side by side, the logos occupy width
       that was empty anyway and the band is far shallower - which is the whole
       point on a phone.

       Placed explicitly rather than by source order: the markup is logo, text,
       logo, which is the right reading order and the right order on a wide
       screen, but here the two logos have to end up in the same column. */
    .band-ribbon-inner{
      display: grid;
      grid-template-columns: auto minmax(0, 1fr);
      grid-template-rows: auto auto;
      align-items: center;
      column-gap: 0.9rem;
      row-gap: 0.35rem;
    }
    /* A FIXED SIZE HERE, not one derived from the title. In this arrangement
       the logos' width is what limits the title, so deriving one from the
       other left them shrinking together and 47px of the column unused. */
    .band-ribbon-inner img{ height: 2.16rem; width: auto; }   /* 10% narrower than 2.4rem */
    /* The two are pinned to the outer edges of the text beside them - the top
       of the upper one to the acronym's capitals, the bottom of the lower one
       to the date's baseline - by js/main.js, which measures both from the
       font's metrics. It needs somewhere to put the offset, hence relative;
       and the row must not centre them first, hence start and end. */
    .band-ribbon-inner > .ribbon-logo:first-of-type{
      grid-column: 1; grid-row: 1; justify-self: center;
      align-self: start; position: relative;
    }
    .band-ribbon-inner > .ribbon-logo:last-of-type {
      grid-column: 1; grid-row: 2; justify-self: center;
      align-self: end; position: relative;
    }
    .ribbon-left{
      grid-column: 2;
      grid-row: 1 / span 2;
      /* THREE TIMES THE SEPARATION between the two lines. The negative margin
         that pulls the date up under the acronym belongs to the wide layout,
         where the pair has to match the height of the logos either side; here
         they are simply two lines and can breathe. */
      row-gap: 0.949rem;
      /* AND NUDGED UP a little. The block is centred against the pair of logos,
         but the two lines are not the same weight: the acronym has ascenders
         and the date below it does not descend as far, so the painted text sat
         4.7px lower in the band than it looked as though it should. Measured
         from the ink, not from the boxes. */
      position: relative;
      top: -4.7px;   /* a third less than the 2.027rem first set */
    }
    /* THE DATE READS AS ONE LINE HERE, as it does everywhere else.

       It used to be split - the when above, the where below - which read
       tidily but cost a whole line of band on the screen with the least of
       it, and left the two logos looking small and loose beside three lines
       of text. The line is allowed to shrink to fit instead. The two halves
       and the separator between them are simply left as they are in the
       markup. */
    .ribbon-left .dateloc{
      margin-top: 0;
      white-space: nowrap;
      /* A TENTH OFF THE LETTER SPACING, 0.079em to 0.0711em. The line is held
         to one line here and shrunk to fit if it will not go, so tighter
         spacing is not only tidier - it buys width, and the fit spends that
         width on larger letters rather than on air between them.

         text-indent goes with it: it exists to cancel the trailing space the
         last letter carries, so that the line sits centred on its letters
         rather than half a space to the left. Change one and the other has to
         follow or the centring drifts. */
      letter-spacing: 0.0711em;
      text-indent: 0.0711em;
    }

    /* ---- BOTH BANDS A FIFTH SHALLOWER ----
       Held upright the header is the screen's biggest expense and the two
       bands above the buttons were 27px and 144px. The date on one line pays
       for most of the second; these two figures pay for the rest.

       The title band is nearly all line box, so the only thing left to give
       was its padding - from 0.38em to 0.194em. What remains looks tighter
       than it is: the line box carries about 2.9px of leading of its own
       above and below the ink, so the visible space is roughly double the
       padding. */
    /* THE BAND IS HELD OPEN BY min-height, NOT BY ITS CONTENTS. With the date
       on one line and the group tightened, the logos and title need only 73px
       - so trimming padding here does nothing at all, and an attempt to do
       just that was silently overridden anyway by the padding SHORTHAND in
       the max-width:900px portrait block further down.

       95px, a tenth off the 106 it stood at and a fifth off the 118 before
       that. Both the band and the row inside it carry the figure: the inner
       one is what actually holds it open, and setting only the outer changes
       nothing at all. The group needs 73px, so there is still room. */
    .band-ribbon{ min-height: 95px; }
    .band-ribbon-inner{ min-height: 95px; }

    /* HOW FAR APART THE TWO LOGOS STAND. Read by js/main.js, which places the
       pair a fixed distance apart, centres it in the band, and then brings
       the two lines of text onto it - so this one figure decides the shape of
       the whole group. Doubled from the 2.5px the edge-aligned version
       happened to leave. */
    :root{ --stack-logo-gap: 5px; }
  }

  @media (max-width: 560px){
    :root{
      --fs-acronym: 2.3625rem;   /* +5% */
      /* THE DATE LINE IS NEVER SMALLER THAN THE PAGE'S OWN TEXT. Everywhere
         else it is a fixed fraction of the acronym, which on a phone put it
         below the size of the news line running underneath it - the place and
         date of the conference, set smaller than the ticker beside it. */
      --fs-dateloc: max(1.134rem, calc(var(--fs-acronym) * 0.451));
      --fs-fullname: 1.1rem;
    }
    .band-title{ padding: 0.38em 1rem; }   /* the same -15% as the base rule */
    .band-ribbon-inner{ padding: 1.125rem 1rem 1.125rem 1rem; }
    .band-news{ padding: 0.357rem 1rem; }
    /* THE SUB-LIST OPENS BESIDE THE BUTTONS, NOT BELOW THEM.

       Pushed into the flow, it shoved every section below it down the panel
       and could take the list past the bottom of the screen. The space to the
       right of the buttons was empty the whole time - the buttons are only as
       wide as their words - so the list goes there instead, always in the same
       place whichever section is opened.

       Both figures are measured from the page by js/main.js: the left edge
       divides the gap between the widest button and the screen edge, and the
       top sits level with the space between the first two buttons. */
    /* ROOM TO BREATHE between the entries. Stacked at their natural line
       height they ran together, with no clear gap between one and the next. */
    /* only the wrapping differs on a phone; the spacing itself is now the
       same everywhere and lives in the base rule above */
    .nav-item.open .dropdown a{ white-space: normal; }


    /* THE SECTION LISTS OPEN TO THE RIGHT, in the space beside the buttons.

       Dropping below the button pushed the seven other sections down the
       screen; here the column stays put and the list uses room that was empty
       anyway. Every list starts from the same point, so it always appears
       where the eye already is - the two figures are measured in
       js/main.js from the widest button and the first two buttons. */
  /* Zero at the top on a phone: the space above the badge is made by the
       hero and the inner block, and this was adding a second helping on top of
       it - 55px against the 32px it has on a desktop, where the same figures
       are meant to hold. */
    .page-main{ padding: 0.000rem 1rem 3rem; }
  }

/* THE TITLE BAND, HELD UPRIGHT: A FIFTH SHALLOWER.
   Nearly all of that band is line box, so its padding was the only thing
   left to give - 0.38em down to 0.194em. What remains looks tighter than it
   is: the line carries about 2.9px of leading above and below the ink, so
   the visible space is roughly twice the padding.

   IT HAS TO SIT AFTER THE max-width:560px BLOCK ABOVE, which sets `padding`
   as a shorthand. A shorthand beats a longhand written earlier whatever the
   specificity, so placed before it this rule measured 27.3px - exactly the
   figure it was meant to change - and looked like it had done nothing. */
@media (orientation: portrait) and (max-width: 640px){
  .band-title{ padding-top: 0.194em; padding-bottom: 0.194em; }

  /* THE WORD "News :" GOES, held upright only.

     At 390px the ribbon has about 300px to work with once the "Menu" button
     has taken its share, and the label was spending 52px of that on a word
     the red band and the scrolling text already announce. Dropped, the
     ticker starts where the label used to and reads 66px more of the line at
     a time - the difference between half a headline and most of one.

     The space to the LEFT of it is unchanged: that is the band's own
     padding, not the label's, so removing the label leaves it exactly as it
     was. The gap after the label goes with the label, since a flex gap needs
     two things to sit between.

     Now done wherever the compact menu appears, not only on a phone - see
     the rule beside .menu-button further up - so nothing is needed here. */

  /* THE MENU PANEL is sized and spaced by the max-width:1024px rule that
     shows the "Menu" button - one place for every mode. Only what is special
     to holding a screen upright is set here, further down: where the panel
     opens, and that it is one column rather than two. */

  /* AND THE CAROUSEL'S OWN PADDING, for the same reason and in the same
     place. The band is not held open by its min-height at these widths but
     by its contents plus 1.125rem of padding above and below, set as a
     SHORTHAND in the max-width:900px portrait block above - which is why the
     longhand written earlier, inside the smaller block, measured no change at
     all. 0.75rem brings the band to the 95px asked for. */
  .band-ribbon-inner{ padding-top: 0.75rem; padding-bottom: 0.75rem; }
}
  @media (max-width: 900px) and (orientation: portrait){
    /* THE RIBBON A TENTH SHALLOWER, and the word "Menu" given the same space
       either side as above and below it.

       This has to sit after EVERY other rule that pads the ribbon - including
       one further up that uses the `padding` shorthand, which overrides a
       longhand `padding-top` no matter how specific the earlier selector was.
       Two earlier attempts had no effect at all for exactly that reason. */
    .band-news{ padding: 0.357rem 1rem; }
    /* THE SUB-LIST OPENS BESIDE THE BUTTONS, NOT BELOW THEM.

       Pushed into the flow, it shoved every section below it down the panel
       and could take the list past the bottom of the screen. The space to the
       right of the buttons was empty the whole time - the buttons are only as
       wide as their words - so the list goes there instead, always in the same
       place whichever section is opened.

       Both figures are measured from the page by js/main.js: the left edge
       divides the gap between the widest button and the screen edge, and the
       top sits level with the space between the first two buttons. */

    /* 0.645em, not the 0.44 that made the four gaps equal ON PAPER. The text
       box includes leading above and below the letters but hugs them at the
       sides, so equal padding leaves the word looking pinched: measured in
       painted pixels it sat 13px below the top edge but only 8.8px in from
       the left. These figures come from the ink, and now read as even. */
    /* the button's side padding is set in its own rule, further up */
  }


  /* reduced motion */
  /* =========================================================
     PROCEEDINGS PAGES (login.php, proceedings.php)
     =========================================================
     These pages carry class "page-proceedings" and are listed alongside every
     other page in the shared card, typography and highlight selectors above.
     That is deliberate and is where their appearance comes from: headings,
     body text, links, tables and the .hl-red / .hl-blue highlights are all
     the SITE's, not their own.

     So there is very little here. The only genuinely new thing on any of
     these pages is the access-code form - no other page has a form - and even
     that is built from the existing palette variables rather than fresh
     colours, so a future change to the site's colours carries over to it.

     IF YOU RESTYLE THE SITE: there should be nothing page-specific to chase
     here. Add .page-proceedings to any new shared selector list, the same way
     the other pages are added, and these pages follow along. */

  /* ---- notices (session expired, wrong code) ----
     Same left-accent-bar language as .key-section and the news cards. */

  /* The username field exists only so browsers offer to remember the access
     code (see the comment in login.php). It must stay in the layout for that
     to work reliably - display:none makes some password managers ignore it -
     so it is collapsed to nothing instead of hidden outright. */
  .gate-username{
    position: absolute;
    width: 1px; height: 1px;
    padding: 0; margin: -1px; border: 0;
    overflow: hidden; clip: rect(0 0 0 0); clip-path: inset(50%);
  }

  /* ---- the access-code form ---- */
  .gate-form{
    display: flex;
    flex-wrap: wrap;         /* button drops below the field when space is tight */
    align-items: center;
    gap: 0.7rem;
    margin: 1.1rem 0 1.3rem;
  }
  .gate-form label{
    font-family: var(--font-nav);
    font-size: 1.15em;      /* the size ordinary text on these pages uses */
    font-weight: 700;
    color: var(--t-heading, var(--navy));
    flex: 0 0 auto;
  }
  .gate-form input[type="password"],
  .gate-form input[type="text"]{
    font-family: var(--font-code);
    letter-spacing: 0.02em;
  }
  .gate-form input[type="password"]{
    flex: 1 1 15rem;         /* grows to fill, wraps rather than overflowing */
    min-width: 0;            /* without this a flex item refuses to shrink */
    font-family: var(--font-nav);
    /* 16px minimum: iOS Safari zooms the whole page in when a focused field
       is smaller than this, which would break the mobile layout */
    font-size: max(1rem, 16px);
    padding: 0.55rem 0.7rem;
    border: 1px solid var(--rule);
    border-radius: 8px;
    background: var(--white);
    color: var(--ink);
  }
  .gate-form input[type="password"]:focus{
    outline: none;
    border-color: var(--blue-btn-mid);
    box-shadow: 0 0 0 3px rgba(15, 79, 150, 0.18);
  }
  /* The submit button borrows the menu bar's button look, so the one control
     on the site that is not in the menu still belongs to the same family. */
  .gate-form button{
    flex: 0 0 auto;
    font-family: var(--font-nav);
    font-weight: 700;
    font-size: var(--fs-nav);
    letter-spacing: 0.6px;
    color: var(--nav-text);
    text-shadow: 1px 1px 0 rgba(0,0,0,0.8);
    background: linear-gradient(180deg, var(--blue-btn-top) 0%, var(--blue-btn-mid) 55%, var(--blue-btn-bot) 100%);
    border: 1px solid rgba(255,255,255,0.12);
    border-radius: 14px;
    /* 44px tall: the minimum comfortable tap target on a touch screen */
    min-height: 44px;
    padding: 0.428em 1.4em;
    cursor: pointer;
    box-shadow:
      inset 0 1px 0 rgba(255,255,255,0.18),
      inset 0 -2px 4px rgba(0,0,0,0.35),
      0 4px 0 var(--blue-btn-bot),
      0 7px 12px rgba(0,0,0,0.4);
  }
  .gate-form button:hover{ filter: brightness(1.08); }
  .gate-form button:focus-visible{
    outline: 2px solid var(--yellow);
    outline-offset: 2px;
  }

  /* The dots that stand in for the typed code are drawn at the font's own
     size, which is small and hard to count. Enlarging them slightly, and
     spacing them out, makes it possible to see at a glance how much has been
     typed. Applies only while the field is hiding its contents: after a
     rejection it becomes type="text" to show the code, and then it is ordinary
     text that should be read normally. */
  .gate-form input[type="password"],
  .gate-form input[type="text"]{
    font-family: var(--font-code);
    letter-spacing: 0.02em;
  }
  /* BOTH STATES MUST BE SET IDENTICALLY. These were on the password type only,
     so when a rejected code was shown - as type="text" - the field rendered at
     a smaller size. Everything measured in em then shrank with it, including
     the box's own width, which lost 77px and pulled the Enter button visibly
     to the left. The masked and the revealed code are the same field and must
     look it. */
  .gate-form input[type="password"],
  .gate-form input[type="text"]{
    font-size: 1.2em;
    letter-spacing: 0.14em;
  }

  /* A REJECTED ACCESS CODE.

     The box does NOT change colour. Colour alone is a poor signal - it says
     nothing to a screen reader, and red/green confusion is common - so the
     rejection is stated in words instead: "Wrong Code" appears inside the box,
     at the right-hand end, and what was typed is made visible so it can be
     read and corrected rather than retyped blind.

     The words sit in a span positioned over the box rather than inside the
     <input>, because an input can only hold plain text. The input gains enough
     right-hand padding that the typed code cannot run underneath them. */
  /* THE BOX IS AS WIDE AS THE CODE, AND NO WIDER, and the "Wrong" message
     sits in the gap between it and the Enter button. The same arrangement on
     every screen: previously the message sat inside the box on a desktop and
     dropped below it on a phone, which meant two layouts to reason about and
     a box that stretched to whatever width happened to be going.

     --code-chars is the length the field accepts; the box is sized from it, so
     changing the limit changes the box automatically and the two cannot fall
     out of step. It works because the field uses a FIXED-WIDTH face, where a
     character really does occupy 1ch whatever it is. */
  .gate-input-wrap{
    --code-chars: 20;
    display: inline-flex;
    align-items: center;
    /* NEVER SHRINKS. It used to be flex: 0 1 auto, and when the "Wrong"
       message appeared beside the box the extra content squeezed the box
       itself - it lost some 60px and dragged the Enter button visibly to the
       left. The row must keep its size whatever is shown in it. */
    flex: 0 0 auto;
    min-width: 0;
  }
  .gate-input-wrap input[type="password"],
  .gate-input-wrap input[type="text"]{
    /* Room for the longest code AS IT IS DISPLAYED WHILE TYPING - that is, as
       masking dots, not as characters.

       THE DOTS ARE WIDER THAN THE CHARACTERS, even in a fixed-width face:
       twenty of them measure about 290px where twenty digits measure 220px.
       Sizing this in "ch" therefore looked right but cut off the last few dots
       as the reader typed. 0.82em per character covers the dot in all three
       engines, with the padding on top. */
    width: calc(var(--code-chars) * 0.82em + 1.4em);
    /* 0 0 auto: the box keeps that width whatever else is in the row. A
       later "flex: 0 1 auto" used to sit in this same block, left over from an
       earlier arrangement, and being last it won - so the box still shrank by
       some 60px when the "Wrong" message appeared, dragging the button with
       it. Two flex declarations in one rule is exactly the kind of thing that
       looks harmless and is not. */
    flex: 0 0 auto;
    max-width: 100%;
    box-sizing: border-box;
    min-width: 0;
  }

  /* The copyright link sits inside a <strong> in a sentence whose other
     emphasised phrases are ordinary bold. Left alone it inherited a heavier
     weight from the link styling and stood out as if it mattered more than the
     phrase beside it; this keeps the two matched. */
  /* A BOLD LINK INSIDE BOLD TEXT, ANYWHERE ON THE SITE.

     Links carry a heavier weight than ordinary bold, so a link written inside
     a <strong> came out at 900 against 700 for the words beside it and read as
     though it mattered more than they did. This was patched three times on
     separate pages before being made general; if a fourth page ever needs it,
     it is already here. */
  section.content-section a strong,
  section.content-section strong a{ font-weight: 700; }

  /* The box keeps its white background and takes a RED FRAME while the code
     it is showing has been rejected. A frame rather than a red fill: the code
     has to stay easy to read - that is the whole reason it is being shown -
     and dark text on a red wash is harder work than it needs to be. */
  .gate-form.code-rejected .gate-input-wrap input{
    border: 2px solid #a81c1c;
    background: #fff;
  }

  /* THE REJECTION IS SHOWN ON THE BUTTON, not beside the box: it turns red and
     its label changes to "Wrong" for three seconds. Nothing else on the row
     competes for width, so the box can hold a full 20-character code even on a
     phone - a separate message alongside it cost about eight characters.

     The red is the same one used for the box frame, so the two read as one
     state rather than two warnings. */
  .gate-form.code-rejected button{
    background: linear-gradient(180deg, #c33 0%, #a81c1c 55%, #7d1414 100%);
    box-shadow:
      inset 0 1px 0 rgba(255,255,255,0.18),
      inset 0 -2px 4px rgba(0,0,0,0.35),
      0 4px 0 #7d1414,
      0 7px 12px rgba(0,0,0,0.4);
    cursor: default;
  }

  /* ON A NARROW SCREEN the code and the message cannot sit side by side: a
     phone offers about 240px, and a full-length code alone needs more than
     that. So the message drops BELOW the field instead, and the field gives
     back the right-hand padding it was reserving - the code stays completely
     visible, which is the thing that matters when you are trying to see what
     you mistyped. */
  @media (max-width: 620px){
    /* The wrap KEEPS its inline-flex layout here, so the box and the "Wrong"
       message stay side by side exactly as on a desktop. Only the button
       moves: it goes underneath, where it has room for a full-width target
       that is easy to hit with a thumb.

       THE FLEX BASIS MUST BE CLEARED. In a column, a flex-basis of 15rem is a
       HEIGHT, not a width, so the wrap reserved 220px of empty space beneath
       itself and left a large gap above the button. */
    /* On a phone the fixed width no longer fits: the box may shrink to the
       space available, at the cost of the longest codes scrolling. Keeping the
       row from overflowing the screen matters more than showing all twenty
       characters at once on a 390px display. */
    .gate-input-wrap{ flex: 0 1 auto; max-width: 100%; }
    .gate-input-wrap input[type="password"],
    .gate-input-wrap input[type="text"]{ flex: 0 1 auto; }
    .gate-form{ flex-direction: column; align-items: flex-start; }
    .gate-form button{ width: 100%; }
  }

  /* The wording still exists for screen readers, which cannot perceive the
     colour change. Visually hidden, but not display:none - a hidden element is
     not announced at all, which would defeat the purpose. */
  .gate-live{
    position: absolute;
    width: 1px; height: 1px;
    margin: -1px; padding: 0; border: 0;
    overflow: hidden; clip: rect(0 0 0 0); clip-path: inset(50%);
  }

  /* ---- the Proceedings and Keynotes tables (Papers page) ----
     Both are plain table.info-table, styled site-wide above; only the column
     behaviour is set here. Titles and author lists are long, so they must be
     allowed to wrap rather than force the table sideways on a phone - without
     table-layout:fixed a long unbroken title widens the whole page.
     Scoped by section id, so it follows the tables if they ever move. */
  /* The tables read at the same size as the text around them. Without this
     they inherit the smaller size that table.info-table uses site-wide, which
     made the paper titles noticeably smaller than the sentence introducing
     them. */
  #Proceedings table.info-table,
  #Keynotes table.info-table{ font-size: 1.15em; }

  #Proceedings table.info-table,
  #Keynotes table.info-table{ table-layout: fixed; }
  /* The Paper and Session columns hold three characters ("142", "S12"), so they
     are sized to their HEADINGS rather than to a guessed width - the heading is
     the widest thing in either column - and their contents are centred beneath
     it. Anything wider would be empty space taken from the Title. */
  /* The Paper and Session columns hold three characters ("142", "S12"), so what
     really sets their width is the HEADING above them, not the content: "Paper"
     measures 2.78em and "Session" 3.83em, plus 0.96em of cell padding. These
     are those figures, so neither column is a pixel wider than it must be and
     the space goes to the Title.

     NOTE the table is table-layout:fixed, where a declared width is taken
     literally rather than as a minimum - "width: 1%" really does give a 1%
     column, with the heading spilling out of it. Any change here must be a
     real measurement, not a small number meaning "as narrow as possible". */
  #Proceedings table.info-table th:nth-child(1),
  #Proceedings table.info-table td:nth-child(1),
  #Keynotes table.info-table th:nth-child(1),
  #Keynotes table.info-table td:nth-child(1){ width: 3.8em; white-space: nowrap; text-align: center; }
  #Proceedings table.info-table th:nth-child(4),
  #Proceedings table.info-table td:nth-child(4){ width: 4.85em; white-space: nowrap; text-align: center; }

  /* Title and Authors used to split the remaining space equally. Titles are far
     longer than author lists, so a quarter of the Authors column is handed to
     the Title: only Authors is given a width, and Title - the one column left
     unsized - takes whatever is left. */
  #Proceedings table.info-table th:nth-child(3),
  #Proceedings table.info-table td:nth-child(3){ width: 30.8%; }
  #Keynotes table.info-table th:nth-child(4),
  #Keynotes table.info-table td:nth-child(4){ width: 4em; }
  #Proceedings table.info-table td,
  #Keynotes table.info-table td{ overflow-wrap: anywhere; }

  /* Column HEADINGS are centred over their columns. The two narrow columns
     centre their contents as well; Title and Authors keep their text
     left-aligned, since centring a wrapped title would be unreadable. */
  #Proceedings table.info-table th,
  #Keynotes table.info-table th{ text-align: center; }

  /* Two pairs of sentences on this page belong together - the one about the
     Access Code and its copyright warning, and the one about the download
     session and its timeout. Closing the gap inside each pair, while leaving
     the normal gap between pairs, is what makes them read as two statements
     rather than four. */
  #Proceedings p.pair-top{ margin-bottom: 0; }
  #Proceedings p.pair-bottom{ margin-top: 0; }

  /* Air around the table. 17px above the heading bar - half as much again as
     the 11.3px it had - and the same amount below the final row, which the
     table did not have at all: its bottom border sat flush against whatever
     followed. Measured, not guessed. */
  #Proceedings table.info-table,
  #Keynotes table.info-table{ margin-top: 17px; margin-bottom: 17px; }

  /* Columns sit closer together: the side padding goes from 0.8em to 0.48em,
     60% of what it was. With the two narrow columns centred, the wider gaps
     were pushing the Title column further right than it needed to be. */
  #Proceedings table.info-table th,
  #Proceedings table.info-table td,
  #Keynotes table.info-table th,
  #Keynotes table.info-table td{ padding-left: 0.48em; padding-right: 0.48em; }

  @media (max-width: 699px){
    /* narrow screens: the ID and the last column both shrink, and the cell
       padding comes in, so the two text columns keep as much room as possible */
    #Proceedings table.info-table th,
    #Proceedings table.info-table td,
    #Keynotes table.info-table th,
    #Keynotes table.info-table td{ padding: 0.5em 0.35em; }
    #Proceedings table.info-table th:nth-child(1),
    #Proceedings table.info-table td:nth-child(1),
    #Keynotes table.info-table th:nth-child(1),
    #Keynotes table.info-table td:nth-child(1){ width: 3.6em; }
    #Proceedings table.info-table th:nth-child(4),
    #Proceedings table.info-table td:nth-child(4){ width: 3.4em; }
    #Keynotes table.info-table th:nth-child(4),
    #Keynotes table.info-table td:nth-child(4){ width: 2.6em; }
  }

  /* ---- the "Conference at a Glance" timetable ----
     A list of items, each led by its time span. The time is given a fixed
     width so the titles line up in a column rather than starting at a ragged
     left edge, which is what makes a timetable scannable. On a narrow screen
     the fixed width is dropped and the time simply sits on its own line -
     forcing a column there would leave too little room for the titles. */
  .page-program .glance-list,
  .page-side-events .glance-list{
    list-style: none;
    margin: 0 0 1.1rem;
    padding: 0;
  }
  /* The whole timetable is indented to begin under the HYPHEN of its day
     heading ("Day 1 - Thursday 1 April 2027"), so the schedule reads as
     hanging beneath the date rather than starting flush with it.

     3.4em is the measured width of "Day 1 " in the heading's own font and
     weight. It is a fixed figure because every heading is "Day N - ..." and
     the digits are the same width, so the hyphen always lands in the same
     place. If the heading format ever changes - "Thursday 1 April" with no
     "Day N" prefix, say - this number has to be re-measured. */
  /* Air around the day heading, derived from the spacing of the rows below it.

     THE BASIS IS FREE SPACE, NOT LINE-HEIGHT. The gap from the bottom of one
     row's text to the top of the next measures ~18px. The line-height is
     ~26px, but that is the PITCH and includes the height of the glyphs
     themselves - using it as "line spacing" inflates anything derived from it
     by about two and a half times, which is what made an earlier attempt at
     these figures look enormous on the page.

       free space between rows  ~18px
       below the heading = 150% of that -> ~27px of ink-to-ink space
       above the heading = 200% of that -> ~37px of ink-to-ink space

     Note both are now measured against the ROW GAP, not against each other.

     THE MARGINS ARE SMALLER THAN THOSE TARGETS. A margin separates element
     BOXES, while the target is measured between INK, and each line box adds
     about 3px of half-leading at top and bottom. So the margins are set ~6px
     under the wanted gap. If you change them, measure the result between text
     rather than trusting the declared value.

     Both are also large enough to win the margin collapse against whatever
     sits above - a paragraph before Day 1, the previous day's list before
     Day 2 - so every heading is spaced identically instead of inheriting its
     neighbour's.

     Restored deliberately: the rule that used to set this was lost when the
     table CSS around it was rescoped, and the headings had been falling back
     to the default paragraph margins ever since. */
  .page-program .day-line{
    margin-top: 1.99rem;      /* -> ~37px of ink-to-ink space, 200% of the row gap */
    margin-bottom: 1.38rem;   /* -> ~27px of ink-to-ink space, 150% of the row gap */
  }

  /* 10% larger than the rows. Written at this specificity because the
     site-wide rule ".page-program section.content-section p" also sets a
     font-size and is more specific than ".page-program .day-line" - a shorter
     selector here is simply ignored. 1.15 x 1.1 = 1.265. */
  /* The date sits between the day and the time with three spaces' worth of air
     either side. Set as a MARGIN rather than as spaces in the markup: three
     literal spaces would collapse to one in HTML, and a run of &nbsp; can only
     ever be a whole number of spaces. 0.834em is three times the measured
     width of a space at this size. */
  .page-program .card-daydate .card-date{ margin: 0 0.834em; }

  /* The day-and-date line, wherever it appears: at the head of each day in the
     timetable, and on every session and keynote card. ONE rule for both, so the
     two cannot drift apart.

     1.38em = 120% of the 1.15em that ordinary text on this page uses. Written
     at this specificity because the site-wide rule for paragraphs inside a
     content section also sets a font-size and is more specific than a lone
     class - a shorter selector here is simply ignored. */
  .page-program section.content-section p.day-line,
  .page-program section.content-section p.card-daydate{ font-size: 1.38em; }

  /* The hyphen has its own element so the space either side of it can be SET
     rather than inherited from a literal space in the markup. A space is
     whatever the font says it is - about 4.7px here - and cannot be adjusted;
     worse, the gap looked wider on the right because the hyphen's own side
     bearing sits inside its advance width on that side only. Equal margins
     make the two visually match. */
  .page-program .day-dash{ margin-right: var(--day-dash-gap); }

  /* Wide enough that "Day 1" clears the hyphen by more than a space: at
     3.15rem the two were 1.2px apart and read as "Day 1- Thursday". Widening
     it moves the timetable indent with it, since both use this one value, so
     the schedule still starts exactly under the hyphen. */
  /* "Day 1" measures ~49.6px at the heading's (now larger) size; +7.05px of
     clearance puts the hyphen at ~56.6px = 3.85rem. The timetable below is
     indented by this same variable, so it still starts exactly under the
     hyphen. Re-measure this if the heading's font size changes again. */
  .page-program{
    /* Wide enough for "Day 1" plus its clearance IN THE WIDEST FONT LIKELY TO
       BE USED. The label is right-aligned inside this column, so the gap to
       the hyphen is exactly --day-dash-gap whatever the font; the slack, if
       any, shows as a small indent BEFORE "Day", which is unobtrusive. Sized
       too small, the label overflows its padding and touches the hyphen - at
       the 120% heading size it needs 4.86rem in the widest fallback font, so
       5.0rem leaves a little margin. RE-MEASURE IF THE HEADING SIZE CHANGES. */
    --day-indent: 5.0rem;
    --day-dash-gap: 0.48rem;   /* the same figure either side of the hyphen */
  }
  .page-program .glance-list{ margin-left: var(--day-indent); }
  /* The label sits in a fixed-width column and is RIGHT-aligned inside it,
     with a padding that is the gap to the hyphen. That padding is the gap, in
     any font - whereas leaving the gap as "whatever is left over in the box"
     made it 11.5px in one browser and 3px in another, purely because the two
     had different fonts available for "Day 1". The hyphen still lands exactly
     at --day-indent, so the timetable below still starts beneath it. */
  .page-program .day-prefix{
    display: inline-block;
    box-sizing: border-box;
    width: var(--day-indent);
    padding-right: var(--day-dash-gap);
    text-align: right;
    /* WITHOUT THIS THE LABEL BREAKS IN TWO. A fixed-width inline-block wraps
       its contents like any other box, and "Day 1" contains a space, so the
       browser happily puts "Day" on one line and "1" on the next - which is
       exactly what it did. The label must stay on one line whatever the box
       width; if the text is wider than the box it now overhangs to the left
       instead, which is harmless because the space to its left is empty. */
    white-space: nowrap;
  }
  /* The timetable is a two-column GRID: times, then everything else.

     A grid rather than one flex row per item, because a grid column is sized
     ONCE for the whole table. Sizing each row independently - which is what
     flex does - left Chromium rounding the column differently from row to row
     and the titles landing 1-2px apart.

     And a grid rather than the hanging indent this replaced, because there the
     run-in to the title was whatever space was left over inside a fixed-width
     time column: it measured 45px in one browser and 20px in another, purely
     because they had different fonts available for the time string. Here the
     gap is a declared figure and identical everywhere.

     Each row is display:contents, so the <li> box disappears and its two
     children become grid items directly. The row's own styling - the italic
     on social items, the ink colour on non-linked ones - still reaches them
     by inheritance. */
  .page-program .glance-list{
    /* rem, not em: this sits on the <ul>, whose font-size differs from the
       rows inside it, so an em here resolved to a smaller gap than intended.
       4.40rem = ~65px, half as much again as the 43px it was. */
    --glance-gap: 4.40rem;
    display: grid;
    grid-template-columns: max-content 1fr;
    column-gap: var(--glance-gap);
    row-gap: 0.75rem;
  }
  .page-program .glance-list > li{ display: contents; }

  .page-program .glance-time,
  .page-side-events .glance-time{
    white-space: nowrap;
    font-family: var(--font-nav);
    font-weight: 700;
    font-variant-numeric: tabular-nums;   /* digits align in a column */
    color: #0000cc;                       /* the site's highlight blue */
  }
  .page-program .glance-body{ min-width: 0; }

  /* A row that is not a link has a black title, so give it a black time too:
     the blue is there to signal "this leads somewhere", and on a coffee break
     it led nowhere and simply looked inconsistent. */
  .page-program .glance-list > li.plain-row .glance-time{ color: var(--ink); }

  /* An accented row - the Conference Opening and the Closure and Awards
     Ceremony - takes the highlight blue for its TIME as well as its title.
     Those rows are not links, so the plain-row rule directly above would
     otherwise ink the time black and leave the title blue on its own.

     IT MUST COME AFTER THAT RULE. The two selectors have identical
     specificity, so the later one wins; placed before it, this had no effect
     at all - which is exactly what the first attempt did. */
  .page-program .glance-list > li.accent-blue .glance-time{ color: #0000cc; }

  /* The accented rows are set in italics as well, time included - the same
     treatment the social items get. The Opening and the Closing Ceremony are
     not sessions with a programme of their own, so italics separate them from
     the technical entries in the same way, while the blue keeps them distinct
     from the breaks and meals. */
  .page-program .glance-list > li.accent-blue,
  .page-program .glance-list > li.accent-blue .glance-time{ font-style: italic; }

  /* A short aside after an item's title - "by foot", "with bus transfers".
     Unemphasised on purpose: it is practical detail, not part of the name, so
     it sits outside the <strong> and stays at normal weight. On the social
     rows it inherits the row's italic, which is what is wanted. */
  .page-program .item-note{
    color: var(--ink);
    font-weight: 400;
  }

  /* The pre-conference list splits in two, and the split is what the colours
     mean:

       .tech-row    the technical programme - sponsor talks and open debates.
                    Highlight blue, upright, time included.
       .social-item everything else - reception, breaks, lunch, the museum
                    visit, the welcome party. Ink, italic, time included, and
                    their links are inked too: the Museum and Welcome Party
                    point at other cards on this same page, which is not the
                    kind of destination the blue is signalling.

     Times follow their row in both cases, so the colour reads consistently
     down the whole column. */
  .page-side-events .preconf-list > li.social-item,
  .page-side-events .preconf-list > li.social-item .glance-time{ color: var(--ink); }
  .page-side-events section.content-section .preconf-list > li.social-item a,
  .page-side-events section.content-section .preconf-list > li.social-item a:visited{
    color: var(--ink);
  }

  .page-side-events .preconf-list > li.tech-row,
  .page-side-events .preconf-list > li.tech-row .glance-time{
    color: #0000cc;
    font-style: normal;
  }
  /* the activity's own name; the description after it stays in ordinary ink */
  .page-side-events .preconf-list > li.tech-row .preconf-body > strong{ color: #0000cc; }
  @media (max-width: 620px){
    /* On a phone the time gets its own line: a side-by-side column would leave
       too little width for the title beside it.

       The whole GRID has to be dismantled, not just the rows. Setting the rows
       to display:block while the <ul> stayed a grid left each row as a single
       grid item that would not shrink, and the page ran ~700px off the side of
       a phone. Both the container and the rows revert to block here. */
    .page-program .glance-list{ display: block; }
    .page-program .glance-list > li{ display: block; margin-bottom: 0.75rem; }
    .page-program .glance-time,
    .page-side-events .glance-time{ display: block; }
    .page-program .glance-body{ display: block; }
  }

  /* The room name, next to the time in the timetable and on each card. It is
     a link to the building map, but a quiet one: the timetable already has
     plenty of blue links for the sessions themselves, and making the rooms
     just as loud would compete with them. A dotted underline marks it as
     clickable without shouting. */
  /* Room links are deliberately NOT in the site's link blue: the timetable
     already carries blue for the sessions themselves, and a second blue for
     every room competed with them. In plain ink the dotted underline is what
     marks them as clickable - quiet, but still discoverable. */
  /* Written as "section.content-section a.room-link" rather than just
     ".room-link" on purpose: the site-wide rule that colours every link inside
     a content section is more specific than a lone class, so a shorter
     selector here silently loses and the rooms stay blue. */
  .page-program section.content-section a.room-link,
  .page-program section.content-section a.room-link:visited{
    color: var(--ink);
    text-decoration: none;
    border-bottom: 1px dotted currentColor;
  }
  .page-program section.content-section a.room-link:hover{
    border-bottom-style: solid;   /* dotted at rest, solid under the pointer */
  }

  /* "Xplore" as a link, UNDERLINED LIKE EVERY OTHER LINK ON THE SITE.

     It used to carry a dotted underline instead, so that it would not break
     the coloured bold run it sits inside - blue on the home page, red on the
     Papers page. The dots read as something other than a link, which is
     exactly what a reader should not have to work out, so it now takes the
     ordinary solid underline.

     It still keeps the colour of the run around it rather than turning the
     site's link blue: the sentence is one coloured phrase and a blue word in
     the middle of it would break the phrase in half. Underline says
     "clickable"; the colour belongs to the sentence.

     Written as "section.content-section a.xplore-link" for the same reason as
     the room links: the site-wide rule colouring every link inside a content
     section beats a lone class, so a shorter selector here would silently lose
     and the word would turn blue after all. */
  section.content-section a.xplore-link,
  section.content-section a.xplore-link:visited{
    color: inherit;
    text-decoration: underline;
    text-underline-offset: 2px;   /* the same offset the other links use */
  }

  /* The separator before a room. The shape itself is an inline SVG built by
     wemdcd_room_arrow() in includes/site-data.php - see the comment there for
     why it is a vector path rather than CSS borders or a text character.
     Only its size and spacing are set here.

     The margin, not a pair of &nbsp; in the markup: a margin can be any value,
     and is symmetric by construction rather than depending on there being no
     stray template whitespace either side. */
  .page-program svg.room-sep{
    display: inline-block;
    width: 1.15em;
    height: 0.92em;
    vertical-align: -0.12em;
    margin: 0 0.84em;
    overflow: visible;        /* round caps must not be clipped at the edges */
  }

  /* An event whose title leads somewhere - the City Tour and the Social Dinner,
     which have their own sections on the Side Events page. Kept in the ordinary
     ink rather than the link blue: these rows are social items, shown in
     italics with the breaks and meals, and colouring them like the sessions
     would pull them out of that group. The dotted underline is what marks them
     as clickable, the same convention the room links use. */
  .page-program section.content-section .glance-list a.event-link,
  .page-program section.content-section .glance-list a.event-link:visited{
    color: var(--ink);
    text-decoration: none;
    border-bottom: 1px dotted currentColor;
  }
  .page-program section.content-section .glance-list a.event-link:hover{
    border-bottom-style: solid;
  }

  /* Social and catering items - receptions, coffee breaks, lunches, the tour,
     the dinner - in italics, TIME INCLUDED, so they read as a different class
     of thing from the sessions and keynotes without needing a second colour or
     an icon. Applies to both timetables, since both use .glance-list. */
  .glance-list > li.social-item,
  .glance-list > li.social-item .glance-time{
    font-style: italic;
  }

  /* Ordinary running text placed inside an emphasised sentence - used on the
     Papers page for "in either A4 or US-letter sizes", which sits beside the
     highlighted template link but is not itself part of the emphasis. Resets
     both the colour and the weight, since it may be nested inside <strong>. */
  .page-papers .plain-note{
    color: var(--ink);
    font-weight: 400;
  }

  /* The web address is given twice the usual space either side, so it stands
     out of the sentence as something to be read off the screen or photographed.
     The sentence already puts one space on each side; this margin adds a second
     - 0.236em is the measured width of a space at this size. */
  .page-welcome .site-url{ margin: 0 0.236em; }

  /* The second line of the welcome sentence - the conference's full name - is
     given twice the usual gap below the line carrying the web address, so the
     address stands on its own. A <br> cannot take a margin, so the line is
     wrapped in a block element instead.

     0.49rem is the measured free space between the two lines (7.2px), added
     again to double it. Re-measure if the lead text size changes. */
  .page-welcome .welcome-line2{
    display: block;
    margin-top: 0.49rem;
  }

  /* A link that stays in the ordinary text colour, used where the words
     themselves are part of a sentence rather than a signpost - "located quite
     conveniently" on the Venue page, which opens a map.

     Written at this specificity on purpose: the site-wide rule that colours
     every link inside a content section is more specific than a lone class,
     so a shorter selector here would simply lose and the link would come out
     blue. The underline is what marks it clickable. */
  .page-venue section.content-section a.map-link,
  .page-venue section.content-section a.map-link:visited{
    color: var(--ink);
    text-decoration: none;
    border-bottom: 1px dotted currentColor;
  }
  .page-venue section.content-section a.map-link:hover{
    border-bottom-style: solid;
  }

  /* ---- the Pre-Conference programme (Side Events page) ----
     The same timetable shape as the Program page, so the two read alike, plus
     the sponsors' logos inline. The logos are DOWNSIZED COPIES in
     images/sponsors-small/ rather than the full-size ones used on the Sponsors
     page: at this size the originals would be roughly four times the bytes for
     no visible gain, which matters on a phone. */
  /* This list uses a flex row rather than the hanging indent the Program page
     uses. The indent trick relies on the first line starting with plain text;
     the inline logos here are taller than the text and push the sponsor name
     onto a line of its own. A flex row keeps the time and the content as two
     solid columns whatever the content's height. */
  /* --preconf-gap is BOTH the space to the right of each start time and the
     indent of the whole list, so the two are equal by definition rather than
     by measurement. The time column is sized to its content (all the times are
     HH:MM, and tabular figures keep them the same width), so the space beside
     it really is this gap and nothing else. */
  .page-side-events .preconf-list{
    --preconf-gap: 2.2rem;   /* rem, not em: the list and its rows sit in
                                different font-size contexts, and an em would
                                resolve to two different lengths */
    margin-left: var(--preconf-gap);
  }

  .page-side-events .preconf-list > li{
    display: flex;
    align-items: baseline;
    gap: var(--preconf-gap);
    margin-bottom: 0.85rem;
    padding-left: 0;
    text-indent: 0;
  }
  /* Sized to its content, not to a fixed width: these rows show a START TIME
     only, so the column is exactly as wide as "HH:MM" and the space beside it
     is the row's gap - a declared figure - rather than whatever is left over,
     which varied from browser to browser. */
  .page-side-events .preconf-list .glance-time{
    flex: 0 0 auto;
    display: inline-block;
    width: auto;
  }
  .page-side-events .preconf-body{ flex: 1 1 auto; min-width: 0; }


  /* The logo and the name are now TWO SEPARATE LINKS with different
     destinations: the logo goes out to the company's own website, the name
     goes to that company's card on our Sponsors page. Keeping them visually
     adjacent while they lead to different places is the point of the small
     gap below - it reads as one unit, but the two targets are distinguishable
     by what you point at. */
  .page-side-events .preconf-logo-link{
    text-decoration: none;
    margin-right: 0.45em;
  }
  .page-side-events .preconf-sponsor{ font-weight: 700; }

  .page-side-events .preconf-logo{
    /* The site's reset sets img{display:block}, which would put each logo on
       a line of its own above the sponsor's name. These few need to sit in
       the run of text, so they opt back in to inline. */
    display: inline-block;
    /* Small on purpose. A taller logo makes the line box taller than the
       surrounding text, which knocks the time column out of alignment and
       leaves ragged vertical gaps down the list. At this size the line height
       is governed by the text, so every row lines up. */
    height: 1.25em;
    width: auto;
    vertical-align: -0.25em;
  }

  .page-side-events .preconf-note{
    font-size: 0.95em;
    color: #4a5560;
  }
  @media (max-width: 620px){
    /* stack on a phone: a fixed time column leaves too little for the rest */
    .page-side-events .preconf-list > li{ display: block; }
    .page-side-events .preconf-list .glance-time{ display: block; }
    .page-side-events .preconf-logo-link{ margin-right: 0.35em; }
  }


  /* ---- a paper in the Program page's session detail ----
     Two lines: "ID - title" (a link when the file exists) then the authors.
     It is an ordinary paragraph; this only tightens the gap between the two
     lines, which would otherwise use the full paragraph line-height. */
  /* A paper in a session's detail card: ID and title in the site's highlight
     blue, authors bold italic in the ordinary ink colour on the line below.
     Colour separates the work from the people; the chairs line above uses the
     same bold italic in ink, which ties the two "who" lines together and sets
     both apart from the blue titles. */
  /* Each paper is a two-column row: its start time on the left in plain ink,
     then the ID/title and the authors indented beside it. A flex row rather
     than a hanging indent, so the second line (the authors) lines up under the
     first instead of running back under the time - the whole point of the
     indent is that the time column stays clear. */
  .page-program .paper-entry{
    display: flex;
    gap: 0.4rem;                 /* the run-in to each column */
    margin-bottom: 0.9rem;
  }
  /* Time and ID get equal breathing room, so the three columns read as a
     regular grid. Both are plain ink: the blue is reserved for the title,
     which is the only part that is ever a link. */
  .page-program .paper-time{
    flex: 0 0 2.6em;             /* about 40% tighter than the first attempt */
    color: var(--ink);
    font-weight: 400;
    font-variant-numeric: tabular-nums;   /* digits line up down the column */
  }
  .page-program .paper-id{
    flex: 0 0 3.2em;             /* fits S14P10 as well as S2P1 */
    text-align: center;          /* the column is wider than most IDs; centring
                                    splits the slack either side instead of
                                    leaving it all to the right, which read as
                                    the ID being shoved against the time */
    color: var(--ink);           /* plain, like the time beside it */
    font-weight: 400;
  }
  .page-program .paper-body{ flex: 1 1 auto; min-width: 0; }

  @media (max-width: 620px){
    /* on a phone the fixed columns cost too much of the title's width: put
       the time and the ID together on one line above it */
    .page-program .paper-entry{ display: block; }
    .page-program .paper-time,
    .page-program .paper-id{ display: inline; }
    .page-program .paper-id{ margin-left: 0.4em; }
    .page-program .paper-body{ display: block; }
  }
  .page-program .paper-authors{
    color: var(--ink);        /* not inherited: <strong> would otherwise pick
                                 up whatever colour the paragraph carries */
    font-style: italic;
  }
  .page-program .chairs-line,
  .page-program .speaker-line{ color: var(--ink); }

  @media (max-width: 560px){
    .gate-form label{ flex: 1 0 100%; }     /* label on its own line */
    .gate-form input[type="password"],
  .gate-form input[type="text"]{
    font-family: var(--font-code);
    letter-spacing: 0.02em;
  }
  .gate-form input[type="password"]{ flex: 1 1 100%; }
    .gate-form button{ flex: 1 1 100%; }    /* full-width button, easy to tap */
  }

  @media (max-height: 500px) and (orientation: landscape){
    .band-bottom{ display: none; }

    .band-title{ position: relative; }
    .title-utils{
      display: inline-flex;
      align-items: center;
      gap: 0.1rem;
      position: absolute;
      right: 0.75rem;
      top: 50%;
      transform: translateY(-50%);
    }
    /* The badge positions itself against the footer in its own rule; in here it
       is one of two things in a row and takes its place from the flex. */
    .title-utils .hit-counter{
      position: static;
      transform: none;
      display: inline-flex;
      font-size: 0.72em;
    }
    /* THE GLYPH IS SMALL, BUT THE TARGET MUST NOT BE. A bare "@" is about 14px
       across, well under the ~24px a fingertip needs, so the box is grown to 24
       square with the character centred in it. The character itself is not
       enlarged.

       Growing it costs nothing here: .title-utils is positioned, so it is out
       of the flow and a taller child cannot push the title band open. The flex
       gap is small to compensate for the 5px of empty target either side of the
       "@", which would otherwise read as too wide a space before the badge. */
    .title-mail{
      color: var(--cyan);
      text-decoration: none;
      font-family: var(--font-util);
      font-weight: 700;
      font-size: 1.05em;
      line-height: 1;
      display: inline-flex;
      align-items: center;
      justify-content: center;
      min-width: 24px;
      min-height: 24px;
    }
    .title-mail:hover{ text-decoration: underline; }

    /* The title is centred in the WHOLE width, so without this its right end
       runs under the badge - the same reservation the footer makes for the
       same reason. */
    .band-title .fullname{ padding-right: 5.6rem; }


    /* ---- THE BUTTON ROW GOES TOO, AS IT DOES ON A PHONE HELD UPRIGHT ----
       The row of eight was kept in landscape because it fitted and cost less
       height than the old hamburger's band. Against a footer-less layout it is
       still 46px that the page could have, so the same "Menu" button used in
       portrait takes over here as well. The panel it opens is the two-column
       one defined further up, which suits a short wide screen.

       These override the (min-width:820px) landscape rules ABOVE, which show
       the full row - equal specificity, so it is source order that decides,
       which is why this whole block sits at the end of the file rather than
       beside the other footer rules. */
    .menu-button{ display: inline-flex; }
    .news-label{ display: none; }
    .band-buttons{ padding-top: 0; padding-bottom: 0; min-height: 0; }
    .nav-inner{ justify-content: space-between; }
    .nav-buttons{
      display: none;
      flex-direction: column;
      position: absolute;
      top: 100%; left: 0; right: 0;
      background: var(--navy-deep);
      padding: 0.8rem;
      box-shadow: 0 10px 20px rgba(0,0,0,0.3);
      gap: 0;
      /* OVER THE NEWS RIBBON, AND BESIDE THE BUTTON THAT OPENED IT.

         Dropped below the ribbon the panel pushed the page a whole band
         further down for nothing. Laid over it instead, the ribbon's height
         costs nothing while the menu is open - but then the panel covered the
         "Menu" button too, leaving no visible way to close it.

         So it starts where that button ends. --menu-w is the button's measured
         width, published by js/main.js beside --news-h; the fallback is only
         for the instant before the script runs. */
      top: 100%;
      left: var(--menu-w, 72px);
      z-index: 42;   /* the news row is 41, and this has to cover it */
    }

    /* FOUR ROWS OF TWO, FILLED DOWNWARDS. "grid-auto-flow: column" with four
       explicit rows is what fills COLUMN BY COLUMN - the default fills row by
       row, which would put a different pair in each row.

       grid-template-columns is reset because the two-column rule further up
       sets it to a pair of max-content tracks; left alone it would fight this.

       ONE GAP EVERYWHERE. The columns are max-content, so each is as wide as
       its own widest button and the SMALLEST gap between any two neighbours is
       the column gap itself - which is set equal to the row gap, so the closest
       pair horizontally is spaced exactly like the pair above and below. The
       figure, 1.15rem, is the one the panel uses on a phone held upright,
       measured off it rather than guessed.

       The same gap is used as the panel's padding, and again between the last
       column and the list that opens beside it, so every space in the block is
       the same size. */
  /* THE COLUMNS ONLY WORK IF THERE IS WIDTH FOR THEM. Below about 568px
     the buttons and the list together are wider than the screen - 22px
     over at 480px, 82px over in a split-screen half-window - and the page
     gained a sideways scrollbar. v65 never did, because its panel was one
     full-width column.

     TWO CONDITIONS, WIDTH AND HEIGHT. Two columns of buttons with a list
     beside them need about 640px across, and four rows need about 209px down
     against the 200px a 320px-tall window has left under the bands. Miss
     either and something goes off an edge, so the arrangement asks for both:
     640px wide and 350px tall. Everything smaller falls back to the single
     column below. */
  @media (min-width: 640px){
      /* ONLY THE ARRANGEMENT IS SET HERE. Hugging the contents, the padding,
         the gap and the --panel-fit flag all come from the max-width:1024px
         rule that shows the "Menu" button, so they are the same in every
         mode. They used to be repeated here as well, and repeated a third
         time for a phone held upright - which is how a tablet held upright
         came to be missed entirely and kept a full-width panel. */
      .nav-buttons.open{
        display: grid;
        grid-template-columns: none;
        grid-auto-flow: column;
        grid-template-rows: repeat(4, max-content);
        justify-content: start;
        align-content: start;
      }

    /* THE SECTION LISTS ARE TIGHTER HERE, by a fifth.

       Sideways there is very little height, and a long list - the nine
       entries of Overview, or the Venue list once it wraps - runs past the
       bottom and has to scroll. The space above and below each entry is the
       only thing that can be given back without touching the lettering, so
       it goes from 0.319em to 0.255em.

       It buys a little under 4px per entry. That is one more entry visible on
       most screens, and it does NOT stop the longest lists scrolling on the
       shortest ones - nothing short of smaller type would. */
    .nav-item.open .dropdown a{ padding-top: 0.204em; padding-bottom: 0.204em; }

    /* SHORTER SCREENS GET FEWER ROWS, NOT MORE.

       Four rows need about 209px of panel, and a landscape phone has roughly
       170 left under the bands once the browser's address bar is showing - so
       the bottom row fell off the edge. The fallback used to be the single
       full-width column, which is EIGHT rows: the tallest arrangement of all,
       chosen exactly when height was scarcest. Revealing the address bar
       turned two neat columns into one long one, for no benefit whatever.

       Fewer rows means more columns, so each step needs more width - which is
       why width is tested alongside height. Three rows need about 161px of
       panel, two about 113px.

       THE WIDTH THRESHOLD IS ABOUT THE LIST, NOT THE BUTTONS. Four columns
       fit at 740px easily enough, but they leave the list beside them so
       narrow that its entries wrap - and a wrapped list is TALLER, which is
       the opposite of what taking a row off was for: 236px of list became
       350. Four columns therefore wait until 820px, where there is width for
       them and for the list. */
    @media (max-height: 349px) and (min-width: 820px){
      .nav-buttons.open{ grid-template-rows: repeat(2, max-content); }
    }
    @media (max-height: 349px) and (max-width: 819px){
      .nav-buttons.open{ grid-template-rows: repeat(3, max-content); }
    }

  }

  /* SMALLER THAN THAT - A SPLIT-SCREEN HALF, OR AN OLD 320-TALL PHONE -
     NOTHING STANDS BESIDE ANYTHING. The arrangement used on a phone held
     UPRIGHT is what fits: one full-width column, the list beside it in the
     room its short words leave.

     It is taller than the window, so it scrolls rather than running off the
     bottom - the only place on the site where the menu does, and better than
     buttons that cannot be reached. */
  @media (max-width: 639px){
    .nav-buttons.open{
      display: flex;
      flex-direction: column;
      /* THE SAME GAP AS EVERY OTHER MODE. Without this the two-column
         landscape rule further up wins with 0.3rem, and the panel ends up
         with one figure for the space between its buttons and another for
         the margin round them - which is what made the arithmetic that sizes
         the panel disagree with itself here and nowhere else. One gap
         everywhere is the whole point. */
      gap: 1.15rem;
      left: var(--menu-w, 72px);
      /* Tall enough to run past the bottom of a window this short, so it
         scrolls rather than putting buttons out of reach. The only place on
         the site where the menu scrolls. */
      max-height: 76vh;
      overflow-y: auto;
      /* The scrollbar is drawn INSIDE the panel, so it ate into the margin on
         the right and left the buttons 5px from the edge instead of 17.
         Reserving the gutter keeps the space whether the bar is showing or
         not, so the margin is the same as everywhere else. */
      scrollbar-gutter: stable;
    }
  }
  .nav-item{ width: auto; }

  /* THE SUB-LISTS OPEN BESIDE THE COLUMNS, NOT UNDER THEIR BUTTON.
     The (min-width:820px) landscape block above places them under the button
     and centred on it, which is right when the whole row of eight is shown -
     but that row is gone here, and "under the button" means over the page and
     off the bottom of a 390px screen. This restores the placement the compact
     menu uses everywhere else: to the right of the columns, in the space they
     leave, from the three variables js/main.js measures.

     The transform needs !important because the rule it has to beat carries
     one and both are `.nav-item.open .dropdown` - equal specificity again, so
     without it the list is still dragged back under its button. */
  .nav-item.open .dropdown{
    position: absolute;
    left: var(--dd-left, 55%);
    top: var(--dd-top, 0.5rem);
    right: auto;
    transform: none !important;
    width: max-content;
    max-width: var(--dd-maxw, 14rem);
    margin-top: 0;
  }

  /* ---- THE RIBBON IS SHALLOWER BY ABOUT A SEVENTH ----
     The band with the logos and the title is by far the largest of the fixed
     areas. Its height is set by its own min-height AND by the title inside
     it, so BOTH have to come down or the type simply holds the band open.
     The logos follow the title's size automatically, being drawn at 1.5x. */
  :root{ --fs-acronym: 2.50rem; }
  /* BOTH the band and the row inside it carry a min-height of 108px, and the
     inner one is what actually holds the band open - setting only the outer
     changed nothing at all. */
  .band-ribbon{ min-height: 92px; }
  .band-ribbon-inner{ min-height: 92px; }

  /* ---- AND THE NEWS LINE BY A TENTH ----
     Only the padding: the text keeps its size and stays centred in what is
     left. */
  .band-news{ padding-top: 0.231rem; padding-bottom: 0.231rem; }

  /* ---- AND THE FULL-TITLE BAND AT THE VERY TOP ----
     The workshop's full name is the least urgent thing on a short screen: it
     is a formality, and the acronym below it says the same in a glance. A
     tenth off the lettering and a seventh off the band it sits in.

     The lettering is trimmed with a VARIABLE, not a font-size. Below about
     820px this line is already limited by the width available, so the fit
     shrinks it to the same place whatever size the stylesheet asks for -
     setting font-size here would have worked on a 844px screen and done
     nothing at all on a 740px one. --fullname-trim is applied after the fit.

     The padding is then set so the band comes out at 85% of its old height,
     allowing for the shorter line the smaller lettering brings with it. */
  :root{ --fullname-trim: 0.90; }
  .band-title{ padding-top: 0.273em; padding-bottom: 0.273em; }
}

@media (prefers-reduced-motion: reduce){
  .news-ticker-track{ animation: none; }
  /* Stepped through by js/main.js instead of scrolling: one item at a time,
     in place. Without this the reader saw only the first item, for ever. */
  .news-ticker-track.news-stepped{ transform: none; }
  .news-stepped .news-item{ display: none; }
  .news-stepped .news-item.news-item-shown{ display: inline; }
  .nav-btn, .dropdown{ transition:none; }
  .band-ribbon-bg img{ transition:none; }
}
