/* Styles for /timeline.html.

   Two halves. The first mirrors the page chrome that index.html carries in its
   inline style block: nav, kicker, section heading, cap grid, footer. It is
   duplicated rather than shared because index.html keeps its CSS inline, and
   splitting that out would be a much larger change to the live page than this
   feature warrants. If you restyle the nav or the section headings over there,
   mirror it here.

   The second half is the timeline itself. Load theme.css BEFORE this file:
   every colour below is a token from it, so the page follows the light and
   dark switch with no palette of its own. The five entry types differ in shape
   as well as colour, so the strands stay separable without relying on hue. */

/* ============================================================ page chrome */

*{margin:0;padding:0;box-sizing:border-box;}
html{scroll-behavior:smooth;}
body{
  background:var(--bg);
  color:var(--fg);
  font-family:'Inter','Helvetica Neue',Helvetica,Arial,sans-serif;
  font-size:16px;
  -webkit-font-smoothing:antialiased;
}
::selection{background:var(--accent);color:var(--bg);}
a{color:inherit;}
img,svg{display:block;}
:focus-visible{outline:2px solid var(--accent);outline-offset:2px;}

body::before{
  content:"";
  position:fixed;inset:0;z-index:200;pointer-events:none;opacity:var(--grain);mix-blend-mode:overlay;
  background-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='120' height='120'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.9' numOctaves='2'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23n)'/%3E%3C/svg%3E");
}

nav{
  position:sticky;top:0;z-index:50;
  height:72px;display:flex;align-items:center;justify-content:space-between;
  padding:0 48px;
  border-bottom:1px solid var(--line);
  background:var(--nav-bg);backdrop-filter:blur(8px);
}
.logo{
  display:flex;align-items:center;gap:.6rem;
  font-size:13px;letter-spacing:.14em;text-transform:uppercase;font-weight:700;
}
.logo a{text-decoration:none;}
.logo .dot{width:6px;height:6px;background:var(--accent);}
nav .links{display:flex;gap:2.4rem;}
nav .links a{
  font-size:12px;letter-spacing:.12em;text-transform:uppercase;font-weight:500;
  text-decoration:none;color:var(--muted);position:relative;padding-bottom:4px;
}
nav .links a::after{
  content:"";position:absolute;left:0;bottom:0;width:0;height:1px;background:var(--accent);
  transition:width 220ms ease;
}
nav .links a:hover{color:var(--fg);}
nav .links a:hover::after{width:100%;}
nav .links a[aria-current="page"]{color:var(--fg);}
nav .links a[aria-current="page"]::after{width:100%;}

@media (max-width:700px){
  nav{padding:.7rem 22px .2rem;height:auto;flex-direction:column;align-items:stretch;gap:.55rem;}
  nav .links{
    gap:1.4rem;overflow-x:auto;scrollbar-width:none;
    padding-bottom:.5rem;-webkit-overflow-scrolling:touch;
  }
  nav .links::-webkit-scrollbar{display:none;}
  nav .links a{white-space:nowrap;}
}

/* The nav is sticky, so a fragment jump would otherwise park the target
   underneath it. Applies to the section anchors the nav itself uses, and to
   the gallery heading the timeline links back to. */
section[id],.tl-entry[id]{scroll-margin-top:88px;}
@media (max-width:700px){section[id],.tl-entry[id]{scroll-margin-top:100px;}}

.kicker{
  display:flex;align-items:center;gap:.8rem;
  font-size:12px;letter-spacing:.18em;text-transform:uppercase;font-weight:600;
  color:var(--accent);margin-bottom:1.4rem;
}
.kicker::before{content:"";width:24px;height:1px;background:var(--accent);}

section{border-bottom:1px solid var(--line);padding:9vh 48px;}
@media (max-width:700px){section{padding:6vh 22px;}}
.section-title{
  font-size:clamp(30px,4.4vw,52px);font-weight:800;letter-spacing:-.02em;line-height:1;
  max-width:14ch;margin-bottom:1.2rem;
}
.lede{font-size:16px;line-height:1.6;color:var(--muted);max-width:56ch;margin-bottom:2rem;}

/* ======================================================== strand palette */

/* Two of the five reuse existing tokens, which already flip with the theme.
   The other two need their own, defined light first and overridden in both
   dark paths, the same shape theme.css uses so the two cannot drift. */
:root{
  --tl-competition:#0e7490;
  --tl-instructor:#15803d;
}
@media (prefers-color-scheme:dark){
  :root:not([data-theme="light"]){
    --tl-competition:#4ec3e0;
    --tl-instructor:#5ec27e;
  }
}
:root[data-theme="dark"]{
  --tl-competition:#4ec3e0;
  --tl-instructor:#5ec27e;
}

.tl-kind-delivery{--strand:var(--accent);}
.tl-kind-qualification{--strand:var(--fg);}
.tl-kind-sailor_qualification{--strand:var(--muted);}
.tl-kind-competition{--strand:var(--tl-competition);}
.tl-kind-instructor_development{--strand:var(--tl-instructor);}

.tl-entry[data-type="delivery"]{--strand:var(--accent);}
.tl-entry[data-type="qualification"]{--strand:var(--fg);}
.tl-entry[data-type="sailor_qualification"]{--strand:var(--muted);}
.tl-entry[data-type="competition"]{--strand:var(--tl-competition);}
.tl-entry[data-type="instructor_development"]{--strand:var(--tl-instructor);}

.tl-draft{
  border:1px dashed var(--accent);color:var(--accent);
  padding:.9rem 1.1rem;margin-bottom:2rem;
  font-size:12.5px;letter-spacing:.04em;
}

/* ============================================================== controls */

.tl-controls{
  border:1px solid var(--line);
}
.tl-controls[hidden]{display:none;}

.tl-row{
  display:flex;flex-wrap:wrap;align-items:center;gap:.7rem 1.4rem;
  padding:1rem 1.4rem;
}
.tl-row + .tl-row{border-top:1px solid var(--line);}

.tl-field{display:flex;flex-wrap:wrap;align-items:center;gap:.6rem 1.1rem;}
.tl-field-search{flex:1 1 24ch;}
.tl-field-types{flex:1 1 auto;}

.tl-field label:not(.tl-filter),.tl-field-label{
  font-size:11px;letter-spacing:.14em;text-transform:uppercase;
  color:var(--muted);flex:none;
}

.tl-controls input[type="search"],
.tl-controls select{
  font:inherit;font-size:13px;color:var(--fg);
  background:var(--bg-2);border:1px solid var(--line);
  padding:.5rem .7rem;
  transition:border-color 220ms ease;
}
.tl-controls input[type="search"]{flex:1 1 12ch;min-width:0;}
.tl-controls select{cursor:pointer;}
.tl-controls input[type="search"]:focus,
.tl-controls select:focus{outline:none;border-color:var(--accent);}
.tl-controls input[type="search"]::placeholder{color:var(--muted);opacity:.75;}

.tl-filter{
  display:inline-flex;align-items:center;gap:.5rem;cursor:pointer;
  font-size:12.5px;color:var(--muted);white-space:nowrap;
}
.tl-filter:hover{color:var(--fg);}
.tl-filter input{accent-color:var(--accent);width:15px;height:15px;cursor:pointer;}
.tl-swatch{width:9px;height:9px;background:var(--strand);flex:none;}
.tl-swatch.tl-kind-competition{transform:rotate(45deg);}
.tl-swatch.tl-kind-instructor_development{border-radius:50%;}
.tl-swatch.tl-kind-sailor_qualification{background:transparent;border:1.5px solid var(--strand);}

.tl-reset{
  margin-left:auto;font:inherit;font-size:11px;letter-spacing:.1em;text-transform:uppercase;
  background:transparent;color:var(--fg);border:1px solid var(--line);
  padding:.5rem .9rem;cursor:pointer;
  transition:border-color 220ms ease,color 220ms ease;
}
.tl-reset:hover{border-color:var(--accent);color:var(--accent);}

.tl-count{
  font-size:12px;letter-spacing:.06em;color:var(--muted);
  margin-top:1.2rem;
}
.tl-count[hidden]{display:none;}

.tl-empty{
  border:1px dashed var(--line);color:var(--muted);
  font-size:13.5px;line-height:1.6;padding:1.6rem 1.8rem;
  max-width:70ch;
}
.tl-empty[hidden]{display:none;}

/* ================================================================= spine */

.tl{
  --gutter:2.5rem;
  margin-top:2.6rem;
  --spine:6px;
  position:relative;
  padding-left:var(--gutter);
}
.tl::before{
  content:"";position:absolute;left:var(--spine);top:.5rem;bottom:.5rem;
  width:1px;background:var(--line);
}
@media (min-width:900px){.tl{--gutter:3.2rem;--spine:9px;}}

.tl-node{
  position:absolute;left:calc(var(--spine) - var(--gutter));top:.45rem;
  width:9px;height:9px;background:var(--strand,var(--muted));
  transform:translateX(-50%);
}

/* Year headings and milestone markers sit on the same spine. */
.tl-year{
  position:relative;
  font-size:12px;letter-spacing:.16em;font-weight:700;color:var(--muted);
  margin:2.6rem 0 1.6rem;
}
.tl-year:first-child{margin-top:0;}
.tl-node-year{
  background:var(--bg);border:1px solid var(--line);
  width:11px;height:11px;top:.05rem;
}

.tl-milestone{
  position:relative;
  font-size:12px;letter-spacing:.06em;text-transform:uppercase;
  color:var(--accent);
  border-top:1px dashed var(--line);border-bottom:1px dashed var(--line);
  padding:.75rem 0;margin:.4rem 0 2.2rem;
}
.tl-node-milestone{
  background:var(--accent);width:7px;height:7px;top:1rem;transform:translateX(-50%) rotate(45deg);
}

/* ================================================================ entries */

.tl-entry{position:relative;padding-bottom:2.8rem;}
.tl-entry[hidden]{display:none;}

/* Point events get a node. The shape carries the type as well as the colour,
   so the strands stay legible without relying on hue alone. */
.tl-entry[data-type="qualification"] .tl-node{border-radius:0;}
.tl-entry[data-type="sailor_qualification"] .tl-node{
  background:var(--bg);border:1.5px solid var(--strand);
}
.tl-entry[data-type="competition"] .tl-node{transform:translateX(-50%) rotate(45deg);}
.tl-entry[data-type="instructor_development"] .tl-node{border-radius:50%;}

/* Ranged blocks render as a span: a rail down the whole card with a cap at
   each end, so a block of work never reads as a single moment. */
.tl-entry[data-span="range"] .tl-node{
  width:3px;height:auto;top:.5rem;bottom:2.9rem;border-radius:3px;
  background:var(--strand);
}
.tl-entry[data-span="range"] .tl-node::before,
.tl-entry[data-span="range"] .tl-node::after{
  content:"";position:absolute;left:50%;transform:translateX(-50%);
  width:11px;height:3px;background:var(--strand);border-radius:2px;
}
.tl-entry[data-span="range"] .tl-node::before{top:0;}
.tl-entry[data-span="range"] .tl-node::after{bottom:0;}

.tl-meta{
  display:flex;flex-wrap:wrap;align-items:center;gap:.5rem .8rem;
  font-size:12px;color:var(--muted);margin-bottom:.5rem;
}
.tl-meta time{letter-spacing:.04em;}
.tl-kind{
  font-size:10.5px;letter-spacing:.1em;text-transform:uppercase;font-weight:600;
  color:var(--strand);
  border:1px solid currentColor;padding:.2rem .5rem;
}
.tl-status{
  font-size:10.5px;letter-spacing:.1em;text-transform:uppercase;font-weight:700;
  padding:.2rem .5rem;background:var(--accent);color:var(--bg);
}
.tl-status-ongoing{background:var(--up);}

.tl-title{
  font-size:19px;font-weight:700;letter-spacing:-.01em;line-height:1.25;
  margin-bottom:.35rem;
}
.tl-org{font-size:13px;color:var(--muted);margin-bottom:.7rem;line-height:1.5;}
.tl-sep{opacity:.5;}
.tl-detail{font-size:14.5px;line-height:1.65;color:var(--muted);max-width:62ch;}

.tl-count{font-size:14px;color:var(--muted);margin-top:.7rem;}
.tl-count b{color:var(--fg);font-size:16px;font-weight:800;}
.tl-count-instructors b{color:var(--tl-instructor);}
.tl-count-note{font-size:12.5px;opacity:.8;}

.tl-syllabus{display:flex;flex-wrap:wrap;gap:.4rem;margin-top:.8rem;}
.tl-syllabus span{
  font-size:10.5px;letter-spacing:.08em;text-transform:uppercase;
  color:var(--muted);border:1px solid var(--line);padding:.22rem .5rem;
}

.tl-outcomes{list-style:none;margin-top:.9rem;display:grid;gap:.35rem;max-width:62ch;}
.tl-outcomes li{
  font-size:13.5px;line-height:1.5;color:var(--muted);
  padding-left:1.1rem;position:relative;
}
.tl-outcomes li::before{
  content:"";position:absolute;left:0;top:.6em;width:5px;height:1px;background:var(--strand);
}

.tl-chips{display:flex;flex-wrap:wrap;gap:.5rem;margin-top:1rem;}
.tl-cite{
  font-size:11px;letter-spacing:.06em;text-transform:uppercase;
  text-decoration:none;color:var(--muted);
  border:1px solid var(--line);padding:.35rem .65rem;
  transition:border-color 220ms ease,color 220ms ease;
}
.tl-cite:hover{border-color:var(--accent);color:var(--accent);}
.tl-cite-gallery{color:var(--accent);border-color:var(--accent);}

/* ============================================================== clusters */

/* Overlapping blocks at different organisations are normal in this trade.
   Bracketing them says "these ran at once" rather than leaving the reader to
   read two rows in the same year as a duplicated entry. */
.tl-cluster{
  position:relative;
  border-left:1px solid var(--line);
  margin:0 0 1rem -1.25rem;padding-left:1.25rem;
}
.tl-cluster-label{
  position:relative;
  font-size:10.5px;letter-spacing:.12em;text-transform:uppercase;
  color:var(--muted);margin-bottom:1.2rem;
}
.tl-node-cluster{
  background:transparent;border:1px dashed var(--muted);
  width:9px;height:9px;top:.1rem;
  left:calc(var(--spine) - var(--gutter) - 1.25rem);
}
.tl-lanes{display:grid;gap:0;}
@media (min-width:820px){
  /* A pair sits side by side, which is the plainest way to say the two ran at
     once. Three or more stay in one column: a grid that wraps would run the
     reader left to right through a list that is sorted top to bottom. */
  .tl-cluster[data-lanes="2"] .tl-lanes{grid-template-columns:1fr 1fr;gap:0 2.4rem;}
  .tl-lanes .tl-entry{padding-bottom:1.6rem;}
  /* Inside a lane the spine is already drawn by the cluster bracket, so each
     lane grows its own short rail rather than reaching back to the main line. */
  .tl-lanes .tl-node{left:-1.1rem;}
}

.tl-empty{color:var(--muted);font-size:14.5px;}
.tl-sr{
  position:absolute;width:1px;height:1px;padding:0;margin:-1px;
  overflow:hidden;clip:rect(0,0,0,0);white-space:nowrap;border:0;
}

/* ========================================================== opened entry */

/* The headline of an entry is turned into a button by /assets/timeline.js.
   None of this applies until it is, so the page never shows a control that
   does nothing. The marker is the type's own shape and colour, which is what
   says the button opens this entry rather than going somewhere else. */
.tl-open{
  font:inherit;color:inherit;background:none;border:0;padding:0;
  text-align:left;cursor:pointer;
  transition:color 220ms ease;
}
.tl-open::after{
  content:"";display:inline-block;vertical-align:middle;
  width:8px;height:8px;margin-left:.6rem;
  border:1.5px solid var(--strand);opacity:.5;
  transition:opacity 220ms ease,background-color 220ms ease;
}
.tl-open:hover{color:var(--strand);}
.tl-open:hover::after{opacity:1;background:var(--strand);}
.tl-open:focus-visible::after{opacity:1;}

.tl-modal{
  position:fixed;inset:0;z-index:400;
  display:flex;align-items:center;justify-content:center;
  padding:clamp(.8rem,3vw,2.4rem);
  background:rgba(8,8,10,.9);
}
.tl-modal[hidden]{display:none;}

/* The type carries through to the panel, so an entry opens under its own
   strand rather than under a colour the dialog picked for itself. */
.tl-modal-panel{
  display:flex;flex-direction:column;min-width:0;
  width:min(720px,100%);max-height:100%;
  background:var(--bg);border:1px solid var(--line);
  border-top:2px solid var(--strand,var(--accent));
}
.tl-modal-panel[data-type="delivery"]{--strand:var(--accent);}
.tl-modal-panel[data-type="qualification"]{--strand:var(--fg);}
.tl-modal-panel[data-type="sailor_qualification"]{--strand:var(--muted);}
.tl-modal-panel[data-type="competition"]{--strand:var(--tl-competition);}
.tl-modal-panel[data-type="instructor_development"]{--strand:var(--tl-instructor);}

.tl-modal-bar{
  display:flex;align-items:center;justify-content:space-between;gap:1rem;
  padding:.8rem 1rem .8rem 1.4rem;border-bottom:1px solid var(--line);
}
.tl-modal-count{font-size:10.5px;letter-spacing:.1em;text-transform:uppercase;color:var(--muted);}
.tl-modal-body{padding:1.6rem 1.4rem;overflow-y:auto;}
.tl-modal-nav{
  display:flex;gap:.6rem;
  padding:.9rem 1.4rem;border-top:1px solid var(--line);
}
.tl-modal-nav[hidden]{display:none;}
.tl-modal-next{margin-left:auto;}

.tl-modal-btn{
  font:inherit;font-size:11px;letter-spacing:.1em;text-transform:uppercase;
  background:transparent;color:var(--muted);border:1px solid var(--line);
  padding:.45rem .8rem;cursor:pointer;
  transition:color 220ms ease,border-color 220ms ease;
}
.tl-modal-btn:hover{color:var(--accent);border-color:var(--accent);}
.tl-modal-close{
  flex:none;width:32px;height:32px;padding:0;
  display:flex;align-items:center;justify-content:center;font-size:13px;
}

/* The card is shown as it stands on the spine, less the spine itself. */
.tl-modal-body .tl-entry{padding-bottom:0;}
.tl-modal-body .tl-title{font-size:22px;margin-bottom:.45rem;}
.tl-modal-body .tl-detail,
.tl-modal-body .tl-outcomes{max-width:none;}

/* ------------------------------------------------------ the written record */

/* Written by scripts/lib/render.mjs into every entry and left hidden until the
   dialog opens it: a delivery block laid out as a job description, a ticket as
   a course description, a race as an event and its result. */
.tl-full{margin-top:1.7rem;border-top:1px solid var(--line);padding-top:1.5rem;}
.tl-full[hidden]{display:none;}

/* The page chrome above styles every section on the page as a band of the
   page itself. These are paragraphs of one entry, so they take none of it. */
.tl-sec{padding:0;border:0;}
.tl-sec + .tl-sec{margin-top:1.5rem;}
.tl-sec h4{
  font-size:10.5px;letter-spacing:.14em;text-transform:uppercase;
  color:var(--muted);margin-bottom:.8rem;
}

.tl-facts{
  display:grid;grid-template-columns:max-content 1fr;gap:.55rem 1.4rem;
  font-size:14px;line-height:1.5;
}
.tl-facts dt{
  font-size:10.5px;letter-spacing:.1em;text-transform:uppercase;
  color:var(--muted);padding-top:.25rem;
}
.tl-note{color:var(--muted);font-size:12.5px;letter-spacing:.02em;}

.tl-links{list-style:none;display:grid;gap:.6rem;font-size:14px;line-height:1.45;}
.tl-facts a,.tl-links a{
  color:var(--fg);text-decoration:none;
  border-bottom:1px solid var(--line);
  transition:color 220ms ease,border-color 220ms ease;
}
.tl-facts a:hover,.tl-links a:hover{color:var(--accent);border-bottom-color:var(--accent);}
.tl-links span,.tl-rest{color:var(--muted);font-size:12.5px;}

.tl-filed{
  margin-top:1.6rem;padding-top:1rem;border-top:1px solid var(--line);
  font-size:11px;letter-spacing:.08em;text-transform:uppercase;color:var(--muted);
}

@media (max-width:620px){
  /* No room to float a panel on a phone, so it takes the screen. */
  .tl-modal{padding:0;}
  .tl-modal-panel{width:100%;height:100%;max-height:100%;border-left:0;border-right:0;border-bottom:0;}
  .tl-facts{grid-template-columns:1fr;gap:.1rem;}
  .tl-facts dt{padding-top:.7rem;}
  .tl-facts dt:first-child{padding-top:0;}
}
