/* ============================================================================
   Sein Minn — academic portfolio, editorial/newsprint direction
   One stylesheet, no build step. Organised top-down:
   tokens > reset > base type > layout > components > page overrides > queries.

   The register is broadsheet, not poster: heavy condensed display type, hard
   rules, zero radius, newsprint stock, single-ink photography. Body copy stays
   in a serif because the recruitment section runs to ~800 words, and a
   newspaper sets its body in serif for exactly that reason.
   ========================================================================== */

/* --- Tokens --------------------------------------------------------------- */

:root {
  /* Newsprint and printing ink. --accent is reserved for links. */
  --paper: #F4F2EC;
  --band: #E7E3D9;
  --ink: #15171A;
  --ink-soft: #585D64;
  --accent: #1B3F63;
  --accent-deep: #0E2438;
  --rule: #C2BDB1;

  /* Type. Archivo is variable on both width and weight, so the display face is
     the body face compressed and blacked — one family doing two jobs. */
  --serif: "STIX Two Text", Georgia, "Times New Roman", serif;
  --sans: "Archivo", "Helvetica Neue", Arial, sans-serif;
  --condensed: 80%;
  --semi-condensed: 90%;

  --t1: 0.8rem;
  --t2: 1rem;
  --t3: 1.25rem;
  --t4: 1.563rem;
  --t5: 1.953rem;
  --t6: 2.441rem;

  --leading-prose: 1.6;
  --leading-tight: 1.04;

  /* Space */
  --s1: 4px;
  --s2: 8px;
  --s3: 12px;
  --s4: 20px;
  --s5: 32px;
  --s6: 52px;
  --s7: 84px;

  /* Rules. A broadsheet has a small vocabulary of weights; these are it. */
  --rule-heavy: 5px;
  --rule-mid: 2px;
  --rule-hair: 1px;

  /* Layout */
  --gutter: var(--s4);
  --measure: 44rem;   /* the reading column */
  --frame: 58rem;     /* masthead, hero headline, footer */
  --portrait: 13rem;
  --date-col: 6rem;

  --motion: 140ms;
}

/* --- Reset ---------------------------------------------------------------- */

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

/* Margins flow one direction: bottom margins plus section padding, so no two
   components ever fight over the gap between them. The single exception is a
   nested list, which has no preceding element to hang a bottom margin off. */
body,
h1,
h2,
h3,
h4,
p,
ul,
ol,
figure,
blockquote {
  margin: 0;
}

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

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

html {
  -webkit-text-size-adjust: 100%;
  font-size: 106.25%; /* 17px root — STIX needs it; the whole rem scale follows */
}

body {
  background-color: var(--paper);
  color: var(--ink);
  font-family: var(--serif);
  font-size: var(--t2);
  line-height: var(--leading-prose);
  font-synthesis-weight: none;
}

/* Justified body text — paragraphs and list items alike. Justification without
   hyphenation opens rivers of whitespace, so the two ship together; hyphens:
   auto relies on the lang attribute every page carries. Headings stay
   ragged-right: a justified headline tears open gaps that read as broken. */
p,
li {
  text-align: justify;
  hyphens: auto;
  /* Never break a word shorter than 6 letters, and never leave fewer than 3
     on either side of the break. */
  hyphenate-limit-chars: 6 3 3;
}

p {
  margin-bottom: var(--s4);
}

p:last-child {
  margin-bottom: 0;
}

/* Section heads are the paper's structural signal: condensed black caps under a
   heavy rule. The rule belongs to the heading, so a section can never be
   separated from its own divider. */
h1,
h2 {
  font-family: var(--sans);
  font-weight: 900;
  font-stretch: var(--condensed);
  font-size: var(--t5);
  line-height: var(--leading-tight);
  text-transform: uppercase;
  letter-spacing: 0.005em;
  color: var(--ink);
  border-top: var(--rule-heavy) solid var(--ink);
  padding-top: var(--s3);
  margin-bottom: var(--s5);
}

/* Article titles run long and stay sentence-case; caps would make them a wall. */
h3 {
  font-family: var(--sans);
  font-weight: 800;
  font-stretch: var(--semi-condensed);
  font-size: var(--t4);
  line-height: 1.12;
  margin-bottom: var(--s4);
}

/* A standfirst label — the smallest step in the display hierarchy. */
h4 {
  font-family: var(--sans);
  font-weight: 700;
  font-stretch: var(--semi-condensed);
  font-size: var(--t1);
  text-transform: uppercase;
  letter-spacing: 0.08em;
  color: var(--ink-soft);
  border-top: var(--rule-hair) solid var(--rule);
  padding-top: var(--s2);
  margin-bottom: var(--s3);
}

strong {
  font-weight: 600;
}

a {
  color: var(--accent);
  text-decoration: underline;
  text-decoration-thickness: 1px;
  text-underline-offset: 2px;
}

a:hover {
  color: var(--accent-deep);
}

:focus-visible {
  outline: var(--rule-mid) solid var(--accent-deep);
  outline-offset: 2px;
}

/* --- Layout primitives ---------------------------------------------------- */

.frame,
.col {
  width: 100%;
  margin-inline: auto;
  padding-inline: var(--gutter);
}

.frame {
  max-width: calc(var(--frame) + 2 * var(--gutter));
}

.col {
  max-width: calc(var(--frame) + 2 * var(--gutter));
}

/* Prose caps at the reading measure and hangs left; the air collects on the
   right, where a broadsheet keeps it. */
.col > * {
  max-width: var(--measure);
}

/* Section rules and the briefs' date column are the exceptions: the rule spans
   the full page width, and the briefs widen by exactly the date column so their
   text still lands on the measure. */
.col > h1,
.col > h2 {
  max-width: none;
}

.col > .news-list {
  max-width: calc(var(--measure) + var(--date-col) + var(--s4));
}

main {
  padding-top: var(--s6);
}

main > * + * {
  margin-top: var(--s7);
}

/* --- Lists ---------------------------------------------------------------- */

ul,
ol {
  padding-left: 1.4em;
}

li {
  margin-bottom: var(--s3);
}

li:last-child {
  margin-bottom: 0;
}

li::marker {
  color: var(--ink-soft);
}

li > ul,
li > ol {
  margin-top: var(--s3);
}

/* --- Masthead ------------------------------------------------------------- */

/* Heavy rule over a hairline: the folio bar every broadsheet opens with. It
   bleeds the full viewport, so it reads as page furniture rather than as a
   section rule that missed its alignment. */
.site-header {
  border-top: var(--rule-heavy) solid var(--ink);
  border-bottom: var(--rule-hair) solid var(--ink);
}

.site-nav {
  display: flex;
  flex-wrap: wrap;
  gap: var(--s2) var(--s5);
  padding-block: var(--s3);
}

.site-nav a {
  font-family: var(--sans);
  font-size: var(--t1);
  font-weight: 600;
  font-stretch: var(--semi-condensed);
  text-transform: uppercase;
  letter-spacing: 0.08em;
  color: var(--ink);
  text-decoration: none;
}

.site-nav a:hover {
  color: var(--accent-deep);
}

.site-nav a[aria-current="page"] {
  font-weight: 900;
  border-bottom: 4px solid var(--ink);
  padding-bottom: 2px;
}

/* --- Hero headline -------------------------------------------------------- */

/* The Knight quotation as a front-page pull-quote: the widest measure on the
   site, condensed black, marked as a quotation by the heavy left rule and the
   oversized opening mark rather than left to read as a headline. */
.epigraph p {
  border-left: var(--rule-heavy) solid var(--ink);
  border-bottom: var(--rule-mid) solid var(--ink);
  padding-left: var(--s5);
  padding-bottom: var(--s5);
  font-family: var(--sans);
  font-weight: 900;
  font-stretch: 82%;
  font-size: clamp(1.5rem, 3.1vw, 2.4rem);
  line-height: 1.22;
  letter-spacing: -0.008em;
  text-align: justify;
  /* Justified display type opens gaps unless the renderer may hyphenate, but a
     headline should only ever break a long word — hence the wide limits. */
  hyphens: auto;
  hyphenate-limit-chars: 9 4 4;
}

/* The opening mark runs inline so the text simply flows after it: no absolute
   positioning to collide with the first line, and justification still works.
   The empty alt text keeps it decorative — it is punctuation framing the
   quotation, not content, and screen readers already get <blockquote>. */
.epigraph p::before {
  content: "\201C" / "";
  font-size: 2.4em;
  line-height: 0;
  vertical-align: -0.34em;
  margin-right: 0.04em;
}

/* --- Profile -------------------------------------------------------------- */

.profile-links {
  font-family: var(--sans);
  font-size: var(--t1);
  font-weight: 600;
  font-stretch: var(--semi-condensed);
  text-transform: uppercase;
  letter-spacing: 0.08em;
  text-align: left;
  hyphens: manual;
  color: var(--rule); /* inherited by the literal "|" separators */
}

.profile-links a {
  color: var(--ink);
  text-decoration: none;
}

.profile-links a:hover {
  color: var(--accent-deep);
}

.profile {
  display: grid;
  gap: var(--s5);
}

/* Press photography: full colour, square corners. */
.portrait {
  width: 100%;
  aspect-ratio: 4 / 5;
  object-fit: cover;
}

/* The nameplate. Same condensed black as the section heads, so the name reads
   as part of the page's structure rather than a caption tacked underneath. */
.portrait-figure figcaption {
  font-family: var(--sans);
  font-weight: 900;
  font-stretch: var(--condensed);
  font-size: var(--t3);
  line-height: 1.05;
  text-transform: uppercase;
  border-top: var(--rule-mid) solid var(--ink);
  padding-top: var(--s2);
  margin-top: var(--s2);
}

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

/* Ruled briefs. News is the only list that is genuinely a time sequence, so it
   is the only one that gets the date column and the rules between entries. */
.news-list {
  list-style: none;
  padding-left: 0;
  border-top: var(--rule-hair) solid var(--rule);
}

.news-list li {
  border-bottom: var(--rule-hair) solid var(--rule);
  padding-block: var(--s4);
  margin-bottom: 0;
  max-width: 80ch;
}

.news-date {
  display: block;
  font-family: var(--sans);
  font-size: var(--t1);
  font-weight: 700;
  font-stretch: var(--semi-condensed);
  text-transform: uppercase;
  letter-spacing: 0.08em;
  color: var(--ink-soft);
  margin-bottom: var(--s1);
}

/* --- Recruitment band ----------------------------------------------------- */

/* The site's only tinted block, boxed top and bottom in heavy rules the way a
   paper boxes a standing notice. Resist adding more. */
.recruit-band {
  background-color: var(--band);
  border-top: var(--rule-heavy) solid var(--ink);
  border-bottom: var(--rule-heavy) solid var(--ink);
  padding-block: var(--s6);
}

/* No rule over the closing sections. The band already carries a heavy rule at
   its own edge, and Contact is followed immediately by the footer's — two heavy
   rules a few lines apart read as a stutter, not a hierarchy. */
.recruit-band h2,
.closing h2 {
  border-top: 0;
  padding-top: 0;
}

.recruit-label {
  margin-bottom: var(--s2);
}

p:has(+ .recruit-label) {
  margin-bottom: var(--s6);
}

/* The requirements were authored as markdown checkboxes ("- [ ]") that plain
   HTML renders literally. They are a real list now. */
.requirements {
  margin-bottom: var(--s3);
}

.requirements li {
  margin-bottom: var(--s2);
}

/* The deadline closing each list qualifies the whole list, not one item, so it
   sits outside it at the same indent. */
.req-note {
  padding-left: 1.4em;
}

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

/* The address is the page's one piece of hard data, so it gets the data
   treatment. The authored spacing inside it is left exactly alone. */
.contact-email {
  font-family: var(--sans);
  font-weight: 900;
  font-stretch: var(--condensed);
  font-size: var(--t4);
  text-align: left;
  hyphens: manual;
}

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

.site-footer {
  margin-top: var(--s7);
  padding-block: 0 var(--s6);
  font-family: var(--sans);
  font-size: var(--t1);
  font-weight: 600;
  font-stretch: var(--semi-condensed);
  text-transform: uppercase;
  letter-spacing: 0.08em;
  color: var(--ink-soft);
  border-top: var(--rule-heavy) solid var(--ink);
}

.site-footer .frame {
  padding-top: var(--s3);
}

/* --- Page overrides ------------------------------------------------------- */

.lab-name {
  font-weight: 600;
}

/* Two-level service lists: the outer item is a category label, not an entry, so
   it takes the label face and the entries under it revert to body copy. */
.venues {
  list-style: none;
  padding-left: 0;
}

.venues > li {
  margin-bottom: var(--s5);
  font-family: var(--sans);
  font-size: var(--t1);
  font-weight: 700;
  font-stretch: var(--semi-condensed);
  text-transform: uppercase;
  letter-spacing: 0.08em;
}

.venues > li > ul {
  margin-top: var(--s4);
  font-family: var(--serif);
  font-size: var(--t2);
  font-weight: 400;
  font-stretch: 100%;
  text-transform: none;
  letter-spacing: normal;
}

.citation-list li {
  margin-bottom: var(--s4);
  max-width: 80ch;
}

.citation-list:has(+ .venues) {
  margin-bottom: var(--s6);
}

.project {
  margin-bottom: var(--s7);
}

.project:last-child {
  margin-bottom: 0;
}

.lede {
  max-width: 72ch;
}

/* --- Media queries -------------------------------------------------------- */

@media (min-width: 768px) {
  :root {
    --gutter: var(--s6);
  }

  main {
    padding-top: var(--s7);
  }

  .profile {
    grid-template-columns: var(--portrait) 1fr;
    align-items: start;
    column-gap: var(--s5);
  }

  /* Dates step out of the flow into their own column, turning the briefs into
     a two-column timeline. The span stays put in the source. */
  .news-list li {
    position: relative;
    padding-left: calc(var(--date-col) + var(--s4));
  }

  .news-date {
    position: absolute;
    left: 0;
    top: var(--s4);
    width: var(--date-col);
    margin-bottom: 0;
  }
}

/* On a phone the quote gets only three or four words to a line, and justifying
   that few opens holes. The display size steps down so more words fit, and the
   hyphenation limits relax so the renderer can actually fill a line instead of
   stretching the spaces. */
/* Wide screens: one column, running the full width of the page.

   Worth knowing: at this width a line carries roughly 120-140 characters,
   against the 60-75 that is comfortable to read — the eye loses its place
   returning to the start of the next line. The owner asked for a single
   full-width column over both a narrower measure and a two-column set, so the
   measure caps are lifted here rather than enforced. */
@media (min-width: 1200px) {
  :root {
    --frame: 84rem;
  }

  /* `.col > .news-list` carries a more specific cap in the base rules, so it
     has to be named here or it stays narrow while everything else widens. */
  .col > *,
  .col > .news-list,
  .lede,
  .news-list li,
  .citation-list li {
    max-width: none;
  }

  .profile {
    grid-template-columns: var(--portrait) 1fr;
  }
}

@media (max-width: 599px) {
  .epigraph p {
    font-size: clamp(1.15rem, 4.6vw, 1.5rem);
    padding-left: var(--s4);
    hyphenate-limit-chars: 6 3 3;
  }

  .epigraph p::before {
    font-size: 2em;
  }
}

@media (prefers-reduced-motion: no-preference) {
  a {
    transition: color var(--motion) ease;
  }
}
