/* Generated by scripts/build-site.mjs. Edit the sources, not this file:
   packages/web/src/styles/tokens.css  (the palette and motion tokens)
   packages/web/src/styles/sinstud.css (everything the public pages draw with) */
:root {
/* ---- the sea ---- */
  --color-abyss: #04101a;        /* page ground, deepest */
  --color-deep: #071827;         /* panels */
  --color-deep-2: #0b2233;       /* raised surfaces, inputs */
  --color-deep-3: #102c40;       /* hover */

  /* ---- fractures ---- */
  --color-rule: #163449;         /* hairline */
  --color-rule-bright: #1f4a66;  /* lit edge of a fracture */

  /* ---- light through water ----
     Raised across the board. The previous --ice-3 (#5D8299) sat around 4.5:1 on
     the abyss ground, and it was carrying every label, unit and placeholder at
     10px uppercase mono — legible in a screenshot, a squint in a studio. The
     floor here is now ~7:1, which is AAA for body text and comfortable for the
     small stuff that does the actual work. */
  --color-ice: #f4fafd;          /* primary text      ~18:1 */
  --color-ice-2: #bdd6e3;        /* secondary         ~12:1 */
  --color-ice-3: #86a9bd;        /* labels, metadata  ~7.4:1 */
  --color-ice-4: #66879b;        /* the genuinely quiet tier, used sparingly */

  /* ---- refraction ---- */
  --color-glass: #8fe0f5;        /* interactive, focus, selection */
  --color-glass-dim: #4ea3bd;

  /* ---- the neutral plate ---- */
  /* Material colour is judged against this, never against the blue. */
  --color-plate: #cfd4d6;

  /* ---- flags ---- */
  --color-flag-draft: #efbc63;   /* unverified */
  --color-flag-hazard: #ff8574;  /* safety */

  --font-sans: 'Inter Tight', ui-sans-serif, system-ui, sans-serif;
  --font-mono: 'IBM Plex Mono', ui-monospace, 'SF Mono', monospace;

  /* Tailwind's sm is 640px, which is wider than every phone — the wordmark would
     never appear on a handset. This is the width at which it fits beside the
     search field. */
  --breakpoint-xs: 400px;

  /* Square, throughout. A rounded corner reads as a card floating over the
     page; a shard has edges. The one exception is anything explicitly
     `rounded-full` — a status dot is a dot, not a tiny pane. */
  --radius-xs: 0px;
  --radius-sm: 0px;
  --radius-md: 0px;
  --radius-lg: 0px;
--ease-glass: cubic-bezier(0.16, 0.84, 0.24, 1);
  --t-quick: 140ms;   /* a control acknowledging a pointer */
  --t-settle: 520ms;  /* a surface arriving on the page */
}

/**
 * SINSTUD — the unbroken sibling.
 *
 * Same material, same light, nothing struck. BrokenGlass is glass that has been
 * hit: cracks radiating from an impact, rules broken into segments, shards
 * displaced. This is the sheet before that happened — one continuous surface,
 * refraction along its length rather than around a break.
 *
 * The palette does not change. What changes is the type, the fracture, and who
 * is allowed to read it.
 */

/* ---------------------------------------------------------------- the fonts
 *
 * Self-hosted, not from a CDN. This project already bundles world-atlas rather
 * than fetching tiles and proxies wire images through its own server, because
 * no third party should learn what you are reading. A font request carries the
 * page, the referrer and the reader's address, and a public site is where that
 * matters most.
 *
 * `font-display: swap` on purpose: Archivo Narrow carries the body text, and a
 * paper that is invisible for 300ms while a font loads is worse than a paper
 * that reflows once.
 */
@font-face {
  font-family: 'Anton';
  font-style: normal;
  font-weight: 400;
  font-display: swap;
  src: url('/fonts/Anton-400-latin.woff2') format('woff2');
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA,
                 U+02DC, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193,
                 U+2212, U+2215, U+FEFF, U+FFFD;
}
@font-face {
  font-family: 'Anton';
  font-style: normal;
  font-weight: 400;
  font-display: swap;
  src: url('/fonts/Anton-400-latin-ext.woff2') format('woff2');
  unicode-range: U+0100-024F, U+0259, U+1E00-1EFF, U+2020, U+20A0-20AB,
                 U+20AD-20CF, U+2113, U+2C60-2C7F, U+A720-A7FF;
}

/* Archivo Narrow, 400/500/600/700 plus italics at 400 and 600. Two subsets
   each: latin-ext is not optional, because citations carry names like Čech. */
@font-face { font-family:'Archivo Narrow'; font-style:normal; font-weight:400; font-display:swap;
  src:url('/fonts/ArchivoNarrow-400-latin.woff2') format('woff2');
  unicode-range:U+0000-00FF,U+0131,U+0152-0153,U+02BB-02BC,U+02C6,U+02DA,U+02DC,U+2000-206F,U+2074,U+20AC,U+2122,U+2191,U+2193,U+2212,U+2215,U+FEFF,U+FFFD; }
@font-face { font-family:'Archivo Narrow'; font-style:normal; font-weight:400; font-display:swap;
  src:url('/fonts/ArchivoNarrow-400-latin-ext.woff2') format('woff2');
  unicode-range:U+0100-024F,U+0259,U+1E00-1EFF,U+2020,U+20A0-20AB,U+20AD-20CF,U+2113,U+2C60-2C7F,U+A720-A7FF; }
@font-face { font-family:'Archivo Narrow'; font-style:normal; font-weight:500; font-display:swap;
  src:url('/fonts/ArchivoNarrow-500-latin.woff2') format('woff2');
  unicode-range:U+0000-00FF,U+0131,U+0152-0153,U+02BB-02BC,U+02C6,U+02DA,U+02DC,U+2000-206F,U+2074,U+20AC,U+2122,U+2191,U+2193,U+2212,U+2215,U+FEFF,U+FFFD; }
@font-face { font-family:'Archivo Narrow'; font-style:normal; font-weight:500; font-display:swap;
  src:url('/fonts/ArchivoNarrow-500-latin-ext.woff2') format('woff2');
  unicode-range:U+0100-024F,U+0259,U+1E00-1EFF,U+2020,U+20A0-20AB,U+20AD-20CF,U+2113,U+2C60-2C7F,U+A720-A7FF; }
@font-face { font-family:'Archivo Narrow'; font-style:normal; font-weight:600; font-display:swap;
  src:url('/fonts/ArchivoNarrow-600-latin.woff2') format('woff2');
  unicode-range:U+0000-00FF,U+0131,U+0152-0153,U+02BB-02BC,U+02C6,U+02DA,U+02DC,U+2000-206F,U+2074,U+20AC,U+2122,U+2191,U+2193,U+2212,U+2215,U+FEFF,U+FFFD; }
@font-face { font-family:'Archivo Narrow'; font-style:normal; font-weight:600; font-display:swap;
  src:url('/fonts/ArchivoNarrow-600-latin-ext.woff2') format('woff2');
  unicode-range:U+0100-024F,U+0259,U+1E00-1EFF,U+2020,U+20A0-20AB,U+20AD-20CF,U+2113,U+2C60-2C7F,U+A720-A7FF; }
@font-face { font-family:'Archivo Narrow'; font-style:normal; font-weight:700; font-display:swap;
  src:url('/fonts/ArchivoNarrow-700-latin.woff2') format('woff2');
  unicode-range:U+0000-00FF,U+0131,U+0152-0153,U+02BB-02BC,U+02C6,U+02DA,U+02DC,U+2000-206F,U+2074,U+20AC,U+2122,U+2191,U+2193,U+2212,U+2215,U+FEFF,U+FFFD; }
@font-face { font-family:'Archivo Narrow'; font-style:normal; font-weight:700; font-display:swap;
  src:url('/fonts/ArchivoNarrow-700-latin-ext.woff2') format('woff2');
  unicode-range:U+0100-024F,U+0259,U+1E00-1EFF,U+2020,U+20A0-20AB,U+20AD-20CF,U+2113,U+2C60-2C7F,U+A720-A7FF; }
@font-face { font-family:'Archivo Narrow'; font-style:italic; font-weight:400; font-display:swap;
  src:url('/fonts/ArchivoNarrow-400i-latin.woff2') format('woff2');
  unicode-range:U+0000-00FF,U+0131,U+0152-0153,U+02BB-02BC,U+02C6,U+02DA,U+02DC,U+2000-206F,U+2074,U+20AC,U+2122,U+2191,U+2193,U+2212,U+2215,U+FEFF,U+FFFD; }
@font-face { font-family:'Archivo Narrow'; font-style:italic; font-weight:400; font-display:swap;
  src:url('/fonts/ArchivoNarrow-400i-latin-ext.woff2') format('woff2');
  unicode-range:U+0100-024F,U+0259,U+1E00-1EFF,U+2020,U+20A0-20AB,U+20AD-20CF,U+2113,U+2C60-2C7F,U+A720-A7FF; }
@font-face { font-family:'Archivo Narrow'; font-style:italic; font-weight:600; font-display:swap;
  src:url('/fonts/ArchivoNarrow-600i-latin.woff2') format('woff2');
  unicode-range:U+0000-00FF,U+0131,U+0152-0153,U+02BB-02BC,U+02C6,U+02DA,U+02DC,U+2000-206F,U+2074,U+20AC,U+2122,U+2191,U+2193,U+2212,U+2215,U+FEFF,U+FFFD; }
@font-face { font-family:'Archivo Narrow'; font-style:italic; font-weight:600; font-display:swap;
  src:url('/fonts/ArchivoNarrow-600i-latin-ext.woff2') format('woff2');
  unicode-range:U+0100-024F,U+0259,U+1E00-1EFF,U+2020,U+20A0-20AB,U+20AD-20CF,U+2113,U+2C60-2C7F,U+A720-A7FF; }

/* --------------------------------------------------------------- the scope
 *
 * Everything is scoped under `.sinstud`. The two sites share a stylesheet, a
 * deployment and a palette; they must not share a type ramp. Nothing here can
 * reach BrokenGlass, which keeps Inter Tight and IBM Plex Mono.
 */
.sinstud {
  --font-display: 'Anton', 'Archivo Narrow', ui-sans-serif, system-ui, sans-serif;
  --font-body: 'Archivo Narrow', ui-sans-serif, system-ui, sans-serif;

  /* SIN is the interactive blue held back, so the two halves of the wordmark
     read as one material at two depths rather than as two colours. The alpha
     is carried in the token rather than in `fill-opacity`, because the SVG
     hard-codes that attribute at 1 and a second knob nobody can see from here
     is how the mark ends up a different weight in two places.
     srgb, not oklab: mixing toward `transparent` in a perceptual space shifts
     the hue on the way down, and this has to stay the same blue. */
  --sin: color-mix(in srgb, var(--color-glass) 60%, transparent);
  --stud: var(--color-ice);

  font-family: var(--font-body);
  color: var(--color-ice-2);
}

/* ═══════════════════════════════════════════════════════════ the type ramp
 *
 * Fluid, and mobile-first in the literal sense: every `clamp()` below starts at
 * the phone value, so the small screen is the design and the desktop is the
 * same design with room. Nothing here has a desktop number that a media query
 * later walks back.
 *
 * Anton is one weight with no italic, so hierarchy is size, tracking and colour
 * — never boldness, because there is none to add. The display steps separate on
 * letter-spacing as much as on size: at this weight tracking is the only thing
 * left to modulate.
 */
.sinstud .s-display {
  font-family: var(--font-display); font-weight: 400;
  font-size: clamp(44px, 13vw, 168px);
  line-height: 0.9; letter-spacing: -0.02em;
  color: var(--color-ice); margin: 0;
  text-wrap: balance;
}
.sinstud .s-title {
  font-family: var(--font-display); font-weight: 400;
  font-size: clamp(26px, 4.6vw, 46px);
  line-height: 1.02; letter-spacing: -0.012em;
  color: var(--color-ice); margin: 0;
  text-wrap: balance;
}
.sinstud .s-section {
  font-family: var(--font-display); font-weight: 400;
  font-size: 13px; letter-spacing: 0.22em; text-transform: uppercase;
  color: var(--color-glass); display: block;
}
/* The magazine's kicker: the line above a headline that says what kind of
   thing it is. Quieter than a section label and always paired with a title. */
.sinstud .s-kicker {
  font-family: var(--font-body); font-size: 11px; font-weight: 600;
  letter-spacing: 0.18em; text-transform: uppercase;
  color: var(--color-flag-draft); display: block; margin-bottom: 8px;
}
.sinstud .s-lede {
  font-size: clamp(16.5px, 2.2vw, 21px); line-height: 1.5;
  color: var(--color-ice-2); max-width: 46ch; margin: 16px 0 0;
  text-wrap: pretty;
}
.sinstud .s-body { font-size: clamp(16px, 1.5vw, 17.5px); line-height: 1.7; color: var(--color-ice-2); }
.sinstud .s-body p { margin: 0 0 1.15em; max-width: 68ch; }
.sinstud .s-small { font-size: 14px; line-height: 1.55; color: var(--color-ice-3); }
.sinstud .s-meta {
  font-size: 11px; letter-spacing: 0.18em; text-transform: uppercase;
  color: var(--color-ice-3); display: block;
}
.sinstud .s-quiet { color: var(--color-ice-4); }

/* ═══════════════════════════════════════════════════════════════ controls */
/* The button, exactly as it was designed.
 *
 * Every number here — the gradient stops, the four inset shadows, the two cast
 * ones, the 22px blur at 180% saturation, the 999px radius, the 160ms
 * transition and the 0.965 press — is from Gabriel's file and is copied rather
 * than reinterpreted. The site's own tokens do not appear in it on purpose:
 * this is the design, and an approximation of it in house colours is not.
 */
.sinstud .s-cta,
.sinstud .s-glass,
.sinstud .s-star {
  /* Border-box, or `min-height` sizes the content and the padding is added on
     top of it — a 46px minimum plus 28px of padding was making a 74px button
     while every number in the rule said 46. */
  box-sizing: border-box;
  position: relative; appearance: none; cursor: pointer; border: none;
  border-radius: 999px;
  color: #ffffff;
  background: linear-gradient(180deg,
    rgba(255,255,255,0.28) 0%, rgba(255,255,255,0.10) 45%, rgba(255,255,255,0.05) 100%);
  backdrop-filter: blur(22px) saturate(180%);
  -webkit-backdrop-filter: blur(22px) saturate(180%);
  box-shadow:
    inset 0 1px 0 rgba(255,255,255,0.6),
    inset 0 -1px 1px rgba(255,255,255,0.18),
    inset 0 0 0 1px rgba(255,255,255,0.22),
    0 18px 40px rgba(4,6,16,0.6),
    0 2px 8px rgba(4,6,16,0.5);
  transition: transform 160ms cubic-bezier(.2,.8,.2,1), box-shadow 200ms ease,
              background 200ms ease;
}
.sinstud .s-cta:hover,
.sinstud .s-glass:hover,
.sinstud .s-star:hover {
  background: linear-gradient(180deg,
    rgba(255,255,255,0.34) 0%, rgba(255,255,255,0.14) 45%, rgba(255,255,255,0.07) 100%);
}
.sinstud .s-cta:active,
.sinstud .s-glass:active,
.sinstud .s-star:active { transform: scale(0.965); }
.sinstud .s-cta:focus-visible,
.sinstud .s-glass:focus-visible,
.sinstud .s-star:focus-visible { outline: 2px solid rgba(255,255,255,.75); outline-offset: 3px; }

/* Sized to the letters rather than to the pane.
 *
 * The file's padding was `clamp(15px,2.2vw,22px) clamp(30px,5vw,54px)` on a
 * long lowercase label at display size. On a four-letter Anton word it put 54px
 * either side of 40px of ink and made a 148x96 box for the word "Read" — the
 * button read as a slab with a caption.
 *
 * Anton is condensed, all-caps here, and has effectively no descender, so the
 * measurements that matter are cap height and tracking, not font-size. Vertical
 * padding is a little over one cap height; horizontal is a shade over twice the
 * vertical, which is what keeps a wide-set capital line from looking pinched
 * without floating in the middle of a field.
 *
 * `line-height: 1` because a leaded line box on all-caps is invisible space
 * that the padding then doubles.
 */
.sinstud .s-cta {
  display: inline-flex; align-items: center; justify-content: center; gap: 9px;
  min-height: 46px;
  padding: 14px 28px;
  /* Tracking adds a space after the final letter that nothing balances on the
     left, so a centred label sits visibly right of centre. Taking one unit of
     it back off the right is the whole fix. */
  padding-right: calc(28px - 0.09em);
  font-family: var(--font-display); font-size: clamp(14px, 1.05vw, 15.5px);
  font-weight: 400; letter-spacing: 0.09em; line-height: 1;
  text-transform: uppercase; text-decoration: none;
}
/* The quiet variant is the same glass, one step back. */
.sinstud .s-cta-quiet {
  background: linear-gradient(180deg,
    rgba(255,255,255,0.16) 0%, rgba(255,255,255,0.06) 45%, rgba(255,255,255,0.03) 100%);
  box-shadow:
    inset 0 1px 0 rgba(255,255,255,0.38),
    inset 0 0 0 1px rgba(255,255,255,0.14),
    0 14px 32px rgba(4,6,16,0.5);
}

.sinstud .s-ctas { display: flex; flex-wrap: wrap; gap: 12px; margin-top: 28px; }

/* A link that reads as a next step. The rule under it draws itself on hover,
   which is the same gesture the nav uses — one language for "go here". */
.sinstud .s-more {
  display: inline-block; margin-top: 16px; position: relative;
  font-family: var(--font-display); font-size: 14px; letter-spacing: 0.1em;
  text-transform: uppercase; color: var(--color-ice); text-decoration: none;
  padding-bottom: 4px;
}
.sinstud .s-more::after {
  content: ''; position: absolute; left: 0; right: 0; bottom: 0; height: 1px;
  background: var(--color-glass); transform-origin: left;
  transform: scaleX(0.28);
  transition: transform var(--t-settle, .4s) var(--ease-glass, ease);
}
.sinstud .s-more:hover::after { transform: scaleX(1); }

.sinstud .s-chips { display: flex; flex-wrap: wrap; gap: 8px; margin-top: 16px; }
.sinstud .s-chip {
  position: relative; font-size: 12px; letter-spacing: .06em; line-height: 1; padding: 8px 15px;
  border-radius: 999px; color: var(--color-ice-2); text-decoration: none;
  border: 1px solid rgba(255,255,255,.16);
}
.sinstud .s-chip-quiet { color: var(--color-ice-4); backdrop-filter: none; }

.sinstud .s-rule {
  height: 1px; border: 0; margin: 0;
  background: linear-gradient(90deg, transparent, var(--color-rule) 8%,
    var(--color-rule-bright) 50%, var(--color-rule) 92%, transparent);
}
.sinstud .s-rule-tight { margin: 20px 0; }
.sinstud .s-rule-normal { margin: 44px 0; }
.sinstud .s-rule-wide { margin: 74px 0; }

.sinstud .s-field {
  width: 100%; max-width: 620px; margin-top: 22px; padding: 16px 18px;
  background: var(--color-deep); color: var(--color-ice);
  border: 1px solid var(--color-rule); border-radius: 2px;
  /* 16px minimum or iOS zooms the page when the field takes focus. */
  font-family: var(--font-body); font-size: 16px;
  transition: border-color var(--t-quick, .14s) ease;
}
.sinstud .s-field:focus { outline: none; border-color: var(--color-glass-dim); }

.sinstud .s-empty {
  border: 1px dashed var(--color-rule); border-radius: 3px;
  padding: 32px 24px; margin-top: 24px; max-width: 68ch;
}

/* ═════════════════════════════════════════════════════════════ the shell
 *
 * Mobile first, and the phone gets the app: a fixed tab bar at the bottom,
 * thumb-height, inside the safe area. The bar is where a hand already is. The
 * orb is the desktop's answer to the same question and appears only there —
 * two menus on one screen is one too many.
 */
/* The bottom padding is clearance for the tab bar, so it only belongs at the
   widths that have one. Carrying it up to the desktop left 140px of dead
   ground under the footer. */
.sinstud.s-shell {
  max-width: 1440px; margin: 0 auto;
  padding: 18px 20px calc(88px + env(safe-area-inset-bottom));
}
@media (min-width: 48rem) { .sinstud.s-shell { padding: 26px 40px 48px; } }
@media (min-width: 90rem) { .sinstud.s-shell { padding: 30px 64px 56px; } }
.sinstud .s-foot { margin-top: 72px; }
html, body { overflow-x: clip; }

/* A page opening on a hero keeps its side padding — the hero pulls its own
   margins back out — but must not have a band of ground above it. */
.sinstud.s-shell-bleed { padding-top: 0; }
.sinstud.s-shell-bleed .s-top { margin-bottom: -70px; }

/* The bar's content stays on the shell's measure while its background runs to
 * the edges of the screen. Painting the background on the element itself
 * stopped it at the shell's max-width, which on a wide screen reads as a
 * floating blue block with two visible seams. The pseudo-element carries the
 * surface and breaks out; the bar carries the content. */
.sinstud .s-top {
  position: sticky; top: 0; z-index: 20; isolation: isolate;
  display: flex; align-items: center; justify-content: space-between; gap: 16px;
  padding: max(12px, env(safe-area-inset-top)) 0 12px;
}
.sinstud .s-top::before {
  content: ''; position: absolute; top: 0; bottom: 0; z-index: -1;
  left: calc(50% - 50vw); width: 100vw;
  background: color-mix(in srgb, var(--color-abyss) 78%, transparent);
  backdrop-filter: blur(16px) saturate(1.3);
  border-bottom: 1px solid transparent;
  transition: border-color .2s ease, background .2s ease;
}
.sinstud .s-top[data-scrolled]::before {
  border-bottom-color: var(--color-rule);
  background: color-mix(in srgb, var(--color-abyss) 93%, transparent);
}
/* Over a hero the bar floats rather than sitting on a band of its own. */
.sinstud.s-shell-bleed .s-top:not([data-scrolled])::before { background: transparent; backdrop-filter: none; }

.sinstud .s-mark { width: 84px; display: block; }
.sinstud .s-mark a { display: block; }
@media (min-width: 48rem) { .sinstud .s-mark { width: 104px; } }

/* The heat, on the mark in the corner.
 *
 * It used to be on the hero wordmark, which meant it existed on one page and
 * then, once that page became the simulator, competed with the material the
 * visitor had just chosen — a glow that recolours STUD is an argument with
 * somebody who picked brass. Up here it is on every page, it is nowhere near
 * anything it can contradict, and it is small enough that a stranger reads it
 * as the logo rather than as a thing that is doing something.
 *
 * `drop-shadow` rather than `box-shadow`: the glow has to follow the
 * letterforms, and drop-shadow traces the alpha channel. The radii are a third
 * of the hero's, because they are around 28px of ink rather than 200px.
 */
.sinstud .s-mark { --heat: 0; --stud: var(--color-ice); }
.sinstud .s-mark svg {
  filter:
    drop-shadow(0 0 calc(var(--heat) * 6px)
      color-mix(in srgb, var(--stud) calc(var(--heat) * 62%), transparent))
    drop-shadow(0 0 calc(var(--heat) * 18px)
      color-mix(in srgb, var(--stud) calc(var(--heat) * 34%), transparent));
  transition: filter 2.4s var(--ease-glass, ease-in-out);
  animation: s-radiance 5.2s var(--ease-glass, ease-in-out) infinite;
}
@keyframes s-radiance {
  50% { filter:
    drop-shadow(0 0 calc(var(--heat) * 9px) color-mix(in srgb, var(--stud) calc(var(--heat) * 78%), transparent))
    drop-shadow(0 0 calc(var(--heat) * 26px) color-mix(in srgb, var(--stud) calc(var(--heat) * 46%), transparent)); }
}
@media (prefers-reduced-motion: reduce) { .sinstud .s-mark svg { animation: none; } }

.sinstud .s-foot { margin-top: 80px; }
.sinstud .s-foot-in { display: flex; flex-wrap: wrap; gap: 14px 28px;
                      justify-content: space-between; align-items: baseline; margin-top: 20px; }

/* ─────────────────────────────────────────────────────────── the tab bar */
.sinstud .s-tabs {
  position: fixed; left: 0; right: 0; bottom: 0; z-index: 60;
  display: grid; grid-auto-flow: column; grid-auto-columns: 1fr;
  padding-bottom: env(safe-area-inset-bottom);
  background: color-mix(in srgb, var(--color-deep) 92%, transparent);
  backdrop-filter: blur(20px) saturate(1.3);
  border-top: 1px solid var(--color-rule);
}
.sinstud .s-tab {
  display: flex; flex-direction: column; align-items: center; gap: 5px;
  /* ~56px of target before the safe area — a thumb, not a pointer. */
  padding: 11px 4px 13px; text-decoration: none;
  color: var(--color-ice-4); font-size: 10px; letter-spacing: .12em;
  text-transform: uppercase; position: relative;
  -webkit-tap-highlight-color: transparent;
}
.sinstud .s-tab svg { width: 21px; height: 21px; display: block; }
.sinstud .s-tab[aria-current="page"] { color: var(--color-ice); }
/* The lit edge grows from the top, the same gesture the app's own tabs use. */
.sinstud .s-tab::before {
  content: ''; position: absolute; top: -1px; left: 50%; right: 50%; height: 2px;
  background: var(--color-glass);
  transition: left .26s var(--ease-glass, ease), right .26s var(--ease-glass, ease);
}
.sinstud .s-tab[aria-current="page"]::before { left: 22%; right: 22%; }
@media (min-width: 48rem) { .sinstud .s-tabs { display: none; } }

/* ─────────────────────────────────────────────────────────── the hamburger */
.sinstud .s-burger {
  position: fixed; top: max(14px, env(safe-area-inset-top));
  right: max(14px, env(safe-area-inset-right)); z-index: 61;
  width: 46px; height: 46px; padding: 0;
  display: none; align-items: center; justify-content: center;
  cursor: pointer; -webkit-tap-highlight-color: transparent;
}
@media (min-width: 48rem) { .sinstud .s-burger { display: flex; } }
.sinstud .s-burger span {
  display: block; position: absolute; left: 15px; right: 15px; height: 1.5px;
  background: var(--color-ice); border-radius: 2px;
  transition: transform .34s var(--ease-glass, ease), opacity .2s ease;
}
.sinstud .s-burger span:nth-child(1) { transform: translateY(-6px); }
.sinstud .s-burger span:nth-child(3) { transform: translateY(6px); }
/* Open, the bars become the cross that closes it — one control, two states. */
.sinstud .s-burger[aria-expanded="true"] span:nth-child(1) { transform: rotate(45deg); }
.sinstud .s-burger[aria-expanded="true"] span:nth-child(2) { opacity: 0; }
.sinstud .s-burger[aria-expanded="true"] span:nth-child(3) { transform: rotate(-45deg); }

/* ──────────────────────────────────────────────────────────── the drawer */
.sinstud .s-menu { position: fixed; inset: 0; z-index: 59; }
.sinstud .s-menu[hidden] { display: none; }
.sinstud .s-scrim {
  position: absolute; inset: 0;
  background: color-mix(in srgb, var(--color-abyss) 72%, transparent);
  backdrop-filter: blur(6px);
  opacity: 0; transition: opacity .34s var(--ease-glass, ease);
}
.sinstud .s-menu[data-open] .s-scrim { opacity: 1; }
.sinstud .s-menu-in {
  position: absolute; top: 0; right: 0; bottom: 0;
  width: min(420px, 86vw); display: flex; flex-direction: column;
  gap: 2px; padding: 96px 34px calc(34px + env(safe-area-inset-bottom));
  background: color-mix(in srgb, var(--color-deep) 82%, transparent);
  backdrop-filter: blur(26px) saturate(1.3);
  border-left: 1px solid color-mix(in srgb, var(--color-ice) 12%, transparent);
  box-shadow: inset 1px 0 0 0 color-mix(in srgb, var(--color-ice) 10%, transparent);
  overflow-y: auto;
  transform: translateX(100%);
  transition: transform .42s var(--ease-glass, cubic-bezier(.2,.7,.3,1));
}
.sinstud .s-menu[data-open] .s-menu-in { transform: none; }
.sinstud .s-menu-link {
  font-family: var(--font-display); font-size: clamp(26px, 3.4vw, 38px);
  line-height: 1.18; text-transform: uppercase; color: var(--color-ice-3);
  text-decoration: none; padding: 10px 0;
  border-bottom: 1px solid color-mix(in srgb, var(--color-rule) 60%, transparent);
  opacity: 0; transform: translateX(16px);
  transition: color .16s ease, opacity .4s ease, transform .4s var(--ease-glass, ease);
}
.sinstud .s-menu[data-open] .s-menu-link {
  opacity: 1; transform: none; transition-delay: calc(var(--i, 0) * 40ms);
}
.sinstud .s-menu-link:hover { color: var(--color-ice); }
.sinstud .s-menu-link[aria-current="page"] { color: var(--color-flag-draft); }

/* ────────────────────────────────────────────────────────── the back button */
.sinstud .s-back {
  display: inline-flex; align-items: center; gap: 9px;
  padding: 9px 17px 9px 13px;
  font-size: 11.5px; letter-spacing: .14em; line-height: 1; text-transform: uppercase;
  color: var(--color-ice-2); text-decoration: none;
}
.sinstud .s-back svg { width: 14px; height: 14px; display: block; }
.sinstud .s-back:hover { color: var(--color-ice); }
/* Its own row under the bar. The home page is where back would go, so it does
   not carry one — `back()` returns nothing there and no row is emitted. */
.sinstud .s-back-row { display: flex; padding: 14px 0 0; }
@media (min-width: 48rem) { .sinstud .s-back-row { padding-top: 18px; } }

/* ═══════════════════════════════════════════════════════════════ the hero */
.sinstud .s-hero {
  position: relative; min-height: 100svh; display: flex; align-items: center;
  overflow: hidden; width: 100vw;
  margin-left: calc(50% - 50vw); margin-right: calc(50% - 50vw); margin-top: -18px;
  background: var(--color-abyss) center / cover no-repeat;
}
@media (min-width: 48rem) { .sinstud .s-hero { margin-top: -26px; } }
.sinstud .s-hero-short { min-height: 58svh; }
.sinstud .s-hero-bg { position: absolute; inset: 0; width: 100%; height: 100%;
                      object-fit: cover; filter: saturate(.85) contrast(1.06); }
.sinstud .s-hero-wash { position: absolute; inset: 0; background: linear-gradient(180deg,
  color-mix(in srgb, var(--color-abyss) 74%, transparent) 0%,
  color-mix(in srgb, var(--color-abyss) 56%, transparent) 42%,
  var(--color-abyss) 100%); }
.sinstud .s-hero-in { position: relative; width: 100%; max-width: 1440px;
                      margin: 0 auto; padding: 96px 20px; }
@media (min-width: 48rem) { .sinstud .s-hero-in { padding: 110px 40px; } }
@media (min-width: 90rem) { .sinstud .s-hero-in { padding: 120px 64px; } }
.sinstud .s-hero-mark { display: block; width: min(620px, 88vw); }
@media (prefers-reduced-motion: reduce) { .sinstud .s-hero-bg { display: none; } }


/* ═══════════════════════════════════════════════════════════ the simulator */
/*
 * The wordmark as an object in a room, and the room's two variables — the light
 * on it and the material it is made of — handed to the visitor.
 *
 * The room is SVG and the object is WebGL, and that split is deliberate. A
 * perspective grid is two dozen straight lines; drawn here it is in the HTML,
 * costs nothing and is on screen before any renderer has downloaded. It is also
 * what the glass half of the word reads through, since SIN is transmissive and
 * the canvas is transparent behind it.
 *
 * Colour comes from two custom properties and nothing else. `--sim-gel` is the
 * light the visitor picked; `--sim-ink` and `--sim-shade` are the lighting
 * state. The gel's value is written by the room module, which needs it as a
 * number for the rim light, so the room and the object are lit from a single
 * declaration rather than from two tables that agree until one is edited.
 */
.sinstud .s-sim {
  --sim-ground: var(--color-abyss);
  --sim-shade: #000000;
  --sim-ink: var(--color-ice);
  --sim-gel: var(--color-ice);
  /* How hard the room falls off at the edges. It is the biggest single lever on
     whether the space reads as lit or as unlit, which is why it is a variable
     the lighting state moves rather than a number in the artwork. */
  --sim-vig: 0.62;
  position: relative; isolation: isolate; overflow: hidden;
  min-height: 100svh; width: 100vw;
  margin-left: calc(50% - 50vw); margin-right: calc(50% - 50vw); margin-top: -18px;
  display: grid; grid-template-rows: auto 1fr auto;
  background: var(--sim-ground);
  transition: background 700ms var(--ease-glass, ease);
}
@media (min-width: 48rem) { .sinstud .s-sim { margin-top: -26px; } }

/* Day is the same room with the lights up, not a white one. A pale hero above
   a dark page is a white rectangle rather than daylight — and the header floats
   over the hero with no background of its own, so an ice wordmark on a pale
   ground would simply disappear. */
.sinstud .s-sim[data-light="studio"] {
  --sim-ground: color-mix(in srgb, var(--color-deep-3) 82%, var(--color-ice));
  --sim-shade: var(--color-abyss);
  --sim-vig: 0.26;
}

.sinstud .s-sim-space {
  position: absolute; inset: 0; width: 100%; height: 100%; display: block;
  pointer-events: none;
}

/* Two strips of the gel, standing in the room. They are the reason a change of
   light reads as a change of light rather than a change of tint: something in
   frame is visibly emitting it. */
.sinstud .s-sim-strip {
  position: absolute; top: 13%; width: 6px; height: 34%; border-radius: 3px;
  background: var(--sim-gel); opacity: 0.72; pointer-events: none;
  box-shadow: 0 0 44px 12px var(--sim-gel);
  transition: background 700ms var(--ease-glass, ease), box-shadow 700ms var(--ease-glass, ease);
}
.sinstud .s-sim-strip-l { left: 7%; }
.sinstud .s-sim-strip-r { right: 7%; }

/* The object. It fills the section and everything else floats over it, so the
   draggable area is the whole hero rather than a box in the middle of it. */
.sinstud .s-sim-stage {
  position: absolute; inset: 0; display: grid; place-items: center;
  /* `pan-y`, never `none`. With `none` a full-height hero on a phone is a trap:
     the finger turns the mark and the page cannot be scrolled past it. Vertical
     belongs to the page and horizontal to the turntable; the pitch axis is the
     price, and it is the right one to pay. */
  touch-action: pan-y;
  cursor: grab; -webkit-tap-highlight-color: transparent;
}
.sinstud .s-sim-stage[data-turning] { cursor: grabbing; }
.sinstud .s-sim-stage:focus-visible { outline: 2px solid var(--color-glass); outline-offset: -6px; }

/* The flat wordmark is the hero until a renderer says otherwise, and it is
   never removed — a lost context, a blocked driver or a failed download all
   land back on it. */
.sinstud .s-sim .s-hero-mark {
  position: relative; z-index: 1;
  transition: opacity 600ms var(--ease-glass, ease);
}
.sinstud .s-sim[data-live] .s-hero-mark { opacity: 0; }
.sinstud .s-sim-stage canvas {
  opacity: 0; transition: opacity 900ms var(--ease-glass, ease);
}
.sinstud .s-sim[data-live] .s-sim-stage canvas { opacity: 1; }

/* Copy and controls float over the object. They take pointer events only where
   there is something to press, so a drag started anywhere else reaches the
   turntable underneath. */
/* Placed by row rather than by order. Everything else in the section is
   absolutely positioned and so out of the grid entirely, which left these two
   as items one and two — the rail landing in the `1fr` middle and stretching
   to fill it, with its hint centred in 375px of nothing. */
.sinstud .s-sim-copy,
.sinstud .s-sim-rail { position: relative; z-index: 2; pointer-events: none; }
.sinstud .s-sim-copy { grid-row: 1; }
.sinstud .s-sim-rail { grid-row: 3; }
/* The standfirst takes pointer events so it can be read and selected like any
   other text; the dead spot it costs the turntable is a corner nobody starts a
   turn in. Everything else in these two boxes is transparent to the pointer, so
   a drag anywhere else in the hero reaches the object. */
.sinstud .s-sim-copy a,
.sinstud .s-sim-copy .s-lede,
.sinstud .s-sim-rail .s-sim-set { pointer-events: auto; }

.sinstud .s-sim-copy { padding: 82px 20px 0; }
@media (min-width: 48rem) { .sinstud .s-sim-copy { padding: 104px 40px 0; } }
@media (min-width: 90rem) { .sinstud .s-sim-copy { padding: 112px 64px 0; } }
.sinstud .s-sim-copy .s-lede { max-width: 34ch; }
.sinstud .s-sim-ctas { margin-top: 22px; }

.sinstud .s-sim-rail {
  display: flex; flex-direction: column; gap: 14px;
  /* Clearance for the tab bar, which is fixed over the bottom of the hero. */
  padding: 0 20px calc(94px + env(safe-area-inset-bottom));
}
@media (min-width: 48rem) {
  .sinstud .s-sim-rail {
    flex-direction: row; align-items: flex-end; justify-content: space-between;
    flex-wrap: wrap; gap: 16px 28px; padding: 0 40px 30px;
  }
}
@media (min-width: 90rem) { .sinstud .s-sim-rail { padding: 0 64px 34px; } }

/* Hidden until the room reports itself running. `visibility` rather than
   opacity alone, so controls for a simulator that never started are also out
   of the tab order rather than invisible and still focusable. */
.sinstud .s-sim-rail { opacity: 0; visibility: hidden; transition: opacity 700ms var(--ease-glass, ease); }
.sinstud .s-sim[data-live] .s-sim-rail { opacity: 1; visibility: visible; }

.sinstud .s-sim-row { display: flex; align-items: flex-end; gap: 18px; }

.sinstud .s-sim-group { display: flex; flex-direction: column; gap: 8px; min-width: 0; }
.sinstud .s-sim-label {
  font-size: 9px; letter-spacing: 0.26em; text-transform: uppercase;
  color: var(--color-ice-3);
}
.sinstud .s-sim-set { display: flex; gap: 8px; align-items: center; }
/* On a phone the five materials do not fit and must not wrap into a second
   row — the hero has one screen and the tab bar already owns the bottom of it. */
@media (max-width: 47.99rem) {
  .sinstud .s-sim-set {
    overflow-x: auto; scrollbar-width: none; -webkit-overflow-scrolling: touch;
    margin: -2px -20px; padding: 2px 20px;
  }
  .sinstud .s-sim-set::-webkit-scrollbar { display: none; }
  .sinstud .s-sim-pill, .sinstud .s-sim-dot { flex: none; }
}

/* Sized to the letters, the same reasoning as `.s-cta`: a little over one cap
   height above and below, and a shade over twice that at the sides. */
.sinstud .s-sim-pill {
  display: inline-flex; align-items: center; justify-content: center; gap: 7px;
  min-height: 34px; padding: 9px 15px; padding-right: calc(15px - 0.16em);
  font-family: var(--font-display); font-size: 10.5px; font-weight: 400;
  letter-spacing: 0.16em; line-height: 1; text-transform: uppercase;
  color: var(--color-ice-2); opacity: 0.72;
}
.sinstud .s-sim-dot {
  display: inline-flex; width: 34px; height: 34px; padding: 5px; opacity: 0.72;
}
.sinstud .s-sim-pill:hover, .sinstud .s-sim-dot:hover { opacity: 0.9; }
.sinstud .s-sim-pill[aria-checked="true"], .sinstud .s-sim-dot[aria-checked="true"] { opacity: 1; }
.sinstud .s-sim-pill[aria-checked="true"] {
  color: #ffffff;
  background: linear-gradient(180deg,
    rgba(255,255,255,0.42) 0%, rgba(255,255,255,0.18) 45%, rgba(255,255,255,0.10) 100%);
}
/* The chosen one wears a ring rather than an outline, because `outline` is
   already spoken for by focus and one control must not say two things with the
   same mark. */
.sinstud .s-sim-dot[aria-checked="true"]::after,
.sinstud .s-sim-pill[aria-checked="true"]::after {
  content: ''; position: absolute; inset: -4px; border-radius: 999px;
  border: 1.5px solid color-mix(in srgb, var(--color-ice) 70%, transparent);
  pointer-events: none;
}

/* Unpainted until the room module fills them in from the material table. A
   swatch guessing at its own material is worse than a grey circle. */
.sinstud .s-sim-swatch {
  display: block; border-radius: 50%; flex: none;
  background: color-mix(in srgb, var(--color-ice) 26%, transparent);
  box-shadow: inset 0 0 0 1px rgba(0,0,0,0.25);
}
.sinstud .s-sim-dot .s-sim-swatch { width: 100%; height: 100%; }
.sinstud .s-sim-pill .s-sim-swatch { width: 9px; height: 9px; }

/* `flex: 1` rather than letting `space-between` place it. At the widths where
   the five materials wrap to their own line, space-between pushes the hint hard
   right and orphans it; taking the leftover space and centring inside it keeps
   the hint between the two groups whether they share a line or not. */
.sinstud .s-sim-hint {
  margin: 0; align-self: center; flex: 1 1 auto; text-align: center;
  font-size: 9.5px; letter-spacing: 0.26em;
  text-transform: uppercase; color: var(--color-ice-3); white-space: nowrap;
}
/* The lit room is a lighter ground, so the quiet tier stops being legible on
   it. Both labels move up one step rather than the ground moving down. */
.sinstud .s-sim[data-light="studio"] .s-sim-label,
.sinstud .s-sim[data-light="studio"] .s-sim-hint { color: var(--color-ice-2); }
@media (max-width: 47.99rem) {
  .sinstud .s-sim-hint { order: -1; align-self: flex-start; flex: none; text-align: left; }
}

/* ══════════════════════════════════════════════════════════════ the blocks */
.sinstud .s-block { margin: 64px 0 0; }
@media (min-width: 48rem) { .sinstud .s-block { margin-top: 96px; } }
.sinstud .s-block:first-child { margin-top: 0; }
.sinstud main > :first-child { margin-top: 0; }

/* Arrival, done by the scroll itself.
 *
 * A page that is simply there has loaded; one that is dealt out has been
 * composed. The first version of this hid every block and had JavaScript
 * reveal them, which made a script load-bearing for whether the site had any
 * content at all — and an IntersectionObserver that does not fire, for any
 * reason, leaves a blank page. That is the same failure this project has
 * already paid for twice.
 *
 * A scroll-driven animation cannot fail that way. Where `view()` is supported
 * the blocks rise as they enter; where it is not, `@supports` never applies and
 * every block is simply visible — the correct fallback, needing no code.
 * Nothing is hidden by anything that has to run first. */
@supports (animation-timeline: view()) {
  @media (prefers-reduced-motion: no-preference) {
    .sinstud [data-reveal] {
      animation: s-reveal linear both;
      animation-timeline: view();
      animation-range: entry 2% entry 46%;
    }
  }
}
@keyframes s-reveal {
  from { opacity: 0; transform: translateY(24px); }
  to { opacity: 1; transform: none; }
}

.sinstud .s-pagehead { padding-top: 30px; }
@media (min-width: 48rem) { .sinstud .s-pagehead { padding-top: 64px; } }
/* A page title is not the wordmark. `.s-display` tops out at 168px because the
   hero is a logo at that size; inheriting it made "Articles" 168px tall with a
   0.9 line-height, which is where the large type was breaking. Its own clamp,
   and a line-height with room for Anton's ascenders when it wraps to two. */
.sinstud .s-pagetitle {
  margin: 12px 0 0;
  font-size: clamp(38px, 7vw, 88px);
  line-height: 0.98;
}
.sinstud .s-pagehead .s-rule { margin-top: 40px; }

/* ─────────────────────────────────────────────────────────────── the feed */
.sinstud .s-feed { display: flex; flex-direction: column; gap: 2px; margin-top: 26px; }
.sinstud .s-post {
  display: grid; gap: 16px; padding: 26px 0;
  border-bottom: 1px solid color-mix(in srgb, var(--color-rule) 70%, transparent);
  grid-template-columns: 1fr;
}
@media (min-width: 40rem) {
  .sinstud .s-post { grid-template-columns: 148px 1fr; gap: 24px; align-items: start; }
}
.sinstud .s-post-m { display: block; overflow: hidden; border-radius: 3px;
                     aspect-ratio: 4 / 3; background: var(--color-deep); }
.sinstud .s-post-m img { width: 100%; height: 100%; object-fit: cover; display: block;
  transition: transform .7s var(--ease-glass, ease); }
.sinstud .s-post:hover .s-post-m img { transform: scale(1.05); }
.sinstud .s-post-t {
  display: block; font-family: var(--font-display);
  font-size: clamp(21px, 3.2vw, 30px); line-height: 1.06;
  color: var(--color-ice); text-decoration: none; margin-bottom: 8px;
  transition: color .16s ease;
}
.sinstud .s-post-t:hover { color: var(--color-glass); }

/* ──────────────────────────────────────────────────────────── the marquee */
.sinstud .s-marquee {
  width: 100vw; margin-left: calc(50% - 50vw); margin-right: calc(50% - 50vw);
  margin-top: 72px; overflow: hidden;
  border-top: 1px solid var(--color-rule); border-bottom: 1px solid var(--color-rule);
  padding: 18px 0; user-select: none;
}
.sinstud .s-marquee-in { display: flex; width: max-content; animation: s-scroll 34s linear infinite; }
.sinstud .s-marquee[data-speed="slow"] .s-marquee-in { animation-duration: 56s; }
.sinstud .s-marquee[data-speed="fast"] .s-marquee-in { animation-duration: 18s; }
.sinstud .s-marquee-run {
  font-family: var(--font-display); font-size: clamp(30px, 6vw, 62px);
  line-height: 1; text-transform: uppercase; letter-spacing: -0.01em;
  color: transparent; -webkit-text-stroke: 1px var(--color-rule-bright);
  padding-right: 0.4em; white-space: nowrap;
}
.sinstud .s-marquee:hover .s-marquee-run { color: var(--color-ice); -webkit-text-stroke-color: transparent; }
.sinstud .s-marquee-run { transition: color .5s ease, -webkit-text-stroke-color .5s ease; }
@keyframes s-scroll { to { transform: translateX(-50%); } }
@media (prefers-reduced-motion: reduce) { .sinstud .s-marquee-in { animation: none; } }

/* ────────────────────────────────────────────────────────────── the splits */
.sinstud .s-splits { display: flex; flex-direction: column; gap: 72px; }
@media (min-width: 48rem) { .sinstud .s-splits { gap: 120px; } }
.sinstud .s-split { display: grid; gap: 22px; align-items: center; grid-template-columns: 1fr; }
@media (min-width: 48rem) {
  .sinstud .s-split { grid-template-columns: 1fr 1fr; gap: 54px; }
  /* Alternating, so the eye crosses the page rather than running down one edge. */
  .sinstud .s-split:nth-child(even) .s-split-m { order: 2; }
}
.sinstud .s-split-m { display: block; overflow: hidden; border-radius: 3px;
                      aspect-ratio: 5 / 4; background: var(--color-deep); }
.sinstud .s-split-m img { width: 100%; height: 100%; object-fit: cover; display: block;
  transition: transform .9s var(--ease-glass, ease); }
.sinstud .s-split:hover .s-split-m img { transform: scale(1.04); }
.sinstud .s-split-in .s-body { margin-top: 14px; }

/* ─────────────────────────────────────────────────────────── the pull quote */
/* The measure goes on the blockquote, not on the figure around it.
 * `ch` resolves against the element's own font-size, and the figure's is body
 * size — so `20ch` there was 146px while the type inside it was 74px. One word
 * per line, twenty lines, fifteen hundred pixels tall. Sized down as well: a
 * 125-character pull quote is a sentence, not a headline. */
.sinstud .s-quote { margin: 64px 0 0; max-width: none; }
@media (min-width: 48rem) { .sinstud .s-quote { margin-left: 6%; } }
.sinstud .s-quote blockquote {
  margin: 0; font-family: var(--font-display);
  font-size: clamp(24px, 3.4vw, 44px); line-height: 1.06;
  letter-spacing: -0.012em; color: var(--color-ice);
  max-width: 24ch; text-wrap: balance;
}
.sinstud .s-quote figcaption { margin-top: 18px; }

/* ──────────────────────────────────────────────────────────── the contents */
.sinstud .s-index { list-style: none; padding: 0; margin: 20px 0 0; }
.sinstud .s-index a {
  display: grid; grid-template-columns: 2.6em 1fr; gap: 4px 14px;
  align-items: baseline; padding: 20px 0; text-decoration: none;
  border-top: 1px solid color-mix(in srgb, var(--color-rule) 70%, transparent);
  transition: padding-left .4s var(--ease-glass, ease);
}
@media (min-width: 48rem) {
  .sinstud .s-index a { grid-template-columns: 3em 1fr auto; padding: 26px 0; }
}
.sinstud .s-index a:hover { padding-left: 14px; }
.sinstud .s-index-n { font-family: var(--font-body); font-size: 12px;
  letter-spacing: .14em; color: var(--color-glass); }
.sinstud .s-index-t { font-family: var(--font-display);
  font-size: clamp(22px, 3.4vw, 34px); line-height: 1.05; color: var(--color-ice); }
/* Empty meta leaves no gap and no grid column standing open for it. */
.sinstud .s-index-m:empty { display: none; }
.sinstud .s-index-m { grid-column: 2; font-size: 11px; letter-spacing: .18em;
  text-transform: uppercase; color: var(--color-ice-4); }
@media (min-width: 48rem) { .sinstud .s-index-m { grid-column: 3; } }

/* ────────────────────────────────────────────────────────────── the profile */
.sinstud .s-profile { display: grid; gap: 22px; grid-template-columns: 1fr; padding-top: 30px; }
@media (min-width: 48rem) {
  .sinstud .s-profile { grid-template-columns: 200px 1fr; gap: 44px; align-items: start; padding-top: 64px; }
}
.sinstud .s-avatar { display: block; width: 120px; aspect-ratio: 1; border-radius: 50%;
  overflow: hidden; background: var(--color-deep); border: 1px solid var(--color-rule); }
@media (min-width: 48rem) { .sinstud .s-avatar { width: 100%; } }
.sinstud .s-avatar img { width: 100%; height: 100%; object-fit: cover; display: block; }
.sinstud .s-profile-n { font-size: clamp(38px, 8vw, 84px); }
.sinstud .s-stats { display: flex; flex-wrap: wrap; gap: 28px; margin: 26px 0 0; }
.sinstud .s-stats div { margin: 0; }
.sinstud .s-stats dd { margin: 4px 0 0; }
.sinstud .s-stat-v { font-family: var(--font-display);
  font-size: clamp(24px, 3.4vw, 34px); line-height: 1; color: var(--color-ice); }

/* ═══════════════════════════════════════════════ cards, tiles, video, grid
 *
 * The card is the magazine's, not the dashboard's: no border, no panel, no box
 * to sit inside. An image, a kicker, a headline and a rule — the frame is the
 * grid it sits in, which is what stops a page of cards reading as a control
 * panel.
 */
.sinstud .s-grid { display: grid; gap: 34px 24px; margin-top: 28px; grid-template-columns: 1fr; }
@media (min-width: 34rem) { .sinstud .s-grid { grid-template-columns: repeat(2, 1fr); } }
@media (min-width: 64rem) { .sinstud .s-grid { grid-template-columns: repeat(3, 1fr); gap: 48px 30px; } }
/* The first card of a feed-style grid takes the full width and reads as the
   lead story — the asymmetry a magazine opens on. */
@media (min-width: 64rem) {
  .sinstud .s-grid > .s-card:first-child { grid-column: span 2; }
  .sinstud .s-grid > .s-card:first-child .s-card-img { aspect-ratio: 16 / 9; }
  .sinstud .s-grid > .s-card:first-child .s-card-t { font-size: clamp(28px, 3vw, 40px); }
}
.sinstud .s-card { display: block; text-decoration: none; color: inherit; }
.sinstud .s-card-img {
  display: block; aspect-ratio: 4 / 3; overflow: hidden;
  background: var(--color-deep); border-radius: 3px;
}
.sinstud .s-card-img img { width: 100%; height: 100%; object-fit: cover; display: block;
  transition: transform .8s var(--ease-glass, ease), filter .5s ease;
  filter: saturate(.92); }
.sinstud .s-card:hover .s-card-img img { transform: scale(1.045); filter: saturate(1.05); }
.sinstud .s-card-in { display: block; padding: 16px 0 0; }
.sinstud .s-card-in > * { display: block; }
.sinstud .s-card-t {
  font-family: var(--font-display); font-size: clamp(21px, 2.4vw, 26px);
  line-height: 1.06; color: var(--color-ice); margin: 8px 0 8px;
  transition: color .16s ease;
}
.sinstud .s-card:hover .s-card-t { color: var(--color-glass); }

/* Portfolio tiles. Ragged on purpose: every third one is tall, so the column
   edges break and the grid reads as hung work rather than as a spreadsheet. */
.sinstud .s-grid-tight { grid-template-columns: repeat(2, 1fr); gap: 12px; }
@media (min-width: 48rem) { .sinstud .s-grid-tight { grid-template-columns: repeat(3, 1fr); gap: 18px; } }
@media (min-width: 75rem) { .sinstud .s-grid-tight { grid-template-columns: repeat(4, 1fr); } }
.sinstud .s-tile { margin: 0; position: relative; overflow: hidden; border-radius: 3px; }
.sinstud .s-tile-img { display: block; aspect-ratio: 1; overflow: hidden; background: var(--color-deep); }
@media (min-width: 48rem) { .sinstud .s-tile:nth-child(3n+1) .s-tile-img { aspect-ratio: 3 / 4; } }
.sinstud .s-tile-img img { width: 100%; height: 100%; object-fit: cover; display: block;
  transition: transform .9s var(--ease-glass, ease); }
.sinstud .s-tile:hover .s-tile-img img { transform: scale(1.06); }
/* The caption rises out of the image rather than sitting under it, so the grid
   stays a wall of work until something is being looked at. */
.sinstud .s-tile figcaption {
  position: absolute; inset: auto 0 0 0; display: block; padding: 30px 14px 14px;
  background: linear-gradient(180deg, transparent, color-mix(in srgb, var(--color-abyss) 88%, transparent));
  transform: translateY(8px); opacity: 0;
  transition: transform .4s var(--ease-glass, ease), opacity .4s ease;
}
.sinstud .s-tile:hover figcaption, .sinstud .s-tile:focus-within figcaption { transform: none; opacity: 1; }
@media (hover: none) { .sinstud .s-tile figcaption { transform: none; opacity: 1; } }
.sinstud .s-tile figcaption > * { display: block; }

.sinstud .s-vid { display: grid; gap: 20px; margin-top: 34px; grid-template-columns: 1fr; }
@media (min-width: 56rem) { .sinstud .s-vid { grid-template-columns: 1.4fr 1fr; gap: 40px; align-items: start; } }
.sinstud .s-vid-p { width: 100%; display: block; background: #000; border-radius: 3px;
                    border: 1px solid var(--color-rule); }
.sinstud .s-vid-in > .s-card-t, .sinstud .s-vid-in > .s-meta { display: block; }

/* A capped height, so a list of videos reads as a list rather than as one
   full-width video after another.
   The width goes with it. Capping the height of a full-width element letterboxes
   inside a bordered box, and the bars are not invisible against a near-black
   page — the border draws the box, so you see a wide black rectangle with a
   video in the middle of it. Letting the element take the film's own aspect
   means the box IS the film: nothing cropped, nothing padded. */
.sinstud .s-vid-p { max-height: 300px; width: auto; max-width: 100%; }

/* ───────────────────────────────────────────── the feed, on a phone
 *
 * Reels: one video a screen, edge to edge, the writing over the picture rather
 * than under it. The desktop arrangement — a player beside a column of text —
 * is a page about videos; this is the videos, which is what a phone is for.
 *
 * `cover` here, where the capped list uses `contain`. A full-bleed frame with
 * bars down both sides is not a reel, and at this size the crop is the format.
 */
@media (max-width: 47.99rem) {
  .sinstud .s-vids {
    width: 100vw; margin-left: calc(50% - 50vw); margin-right: calc(50% - 50vw);
    margin-top: 22px;
  }
  /* Proximity, not mandatory, and only on a page that has a feed: the heading
     above and the footer below still have to be reachable, and a mandatory
     snap makes the page fight anybody trying to leave the videos. */
  html:has(.s-vids) { scroll-snap-type: y proximity; }

  .sinstud .s-vid {
    position: relative; display: block; margin: 0 0 3px; overflow: hidden;
    /* The chrome owns the top and the bottom of the screen; this is what is
       left, so a video is a screenful without sitting under the tab bar. */
    height: calc(100svh - 132px - env(safe-area-inset-bottom));
    background: #000; scroll-snap-align: center;
  }
  .sinstud .s-vid-p {
    position: absolute; inset: 0; width: 100%; height: 100%;
    max-height: none; object-fit: cover; border: 0; border-radius: 0;
  }
  .sinstud .s-vid-in {
    position: absolute; left: 0; right: 0; bottom: 0; z-index: 2;
    /* The scrim runs to the bottom edge so the player's own controls are
       legible against it; the words stop above them. Without the clearance the
       caption and the scrubber occupied the same strip and you could read the
       timeline through the text. */
    padding: 64px 18px calc(76px + env(safe-area-inset-bottom));
    /* A scrim rather than a panel: the picture keeps going behind the words. */
    background: linear-gradient(180deg,
      transparent 0%, rgba(0,0,0,0.55) 42%, rgba(0,0,0,0.86) 100%);
    pointer-events: none;
  }
  .sinstud .s-vid-in > .s-card-t { font-size: 17px; }
  .sinstud .s-vid-in .s-body { font-size: 14.5px; line-height: 1.5; margin-top: 6px; }
  .sinstud .s-vid-in .s-body p { max-width: none; margin-bottom: 0.5em; }

  /* Three lines, then "more" — a caption is a caption and the video is what is
     being looked at. Tapping opens it; the text takes pointer events back for
     exactly that, so everywhere else on the frame still reaches the player. */
  .sinstud .s-vid-in [data-caption] {
    pointer-events: auto; cursor: pointer;
    display: -webkit-box; -webkit-box-orient: vertical; -webkit-line-clamp: 3;
    overflow: hidden;
  }
  .sinstud .s-vid-in [data-caption][data-open] {
    display: block; max-height: 42svh; overflow-y: auto;
    -webkit-overflow-scrolling: touch; overscroll-behavior: contain;
  }
  /* On the caption's parent, not the caption.
     `-webkit-line-clamp` clips the element's content — which includes its own
     `::after` — so the marker saying there was more to read was the first thing
     hidden for having more to read. */
  .sinstud .s-vid-in:has([data-caption][data-clamped])::after,
  .sinstud .s-vid-in:has([data-caption][data-open])::after {
    content: 'more'; display: block; margin-top: 4px; pointer-events: none;
    font-size: 11px; letter-spacing: .16em; text-transform: uppercase;
    color: var(--color-ice-3);
  }
  .sinstud .s-vid-in:has([data-caption][data-open])::after { content: 'less'; }

  /* The controls are the one thing that must stay reachable under the scrim. */
  .sinstud .s-vid-p::-webkit-media-controls { z-index: 3; }
}

.sinstud .s-cta-block { max-width: 54ch; }

/* ═════════════════════════════════════════════════════════════ page moves
 *
 * Cross-document view transitions, so following a link fades between pages
 * instead of blanking to white and rebuilding. Browsers without it navigate
 * exactly as before — there is no fallback to write and nothing to feature
 * detect, which is the reason to use the platform's version rather than
 * intercepting clicks and animating by hand.
 */
@view-transition { navigation: auto; }
@media (prefers-reduced-motion: no-preference) {
  ::view-transition-old(root) { animation: s-vt-out .28s var(--ease-glass, ease) both; }
  ::view-transition-new(root) { animation: s-vt-in .42s var(--ease-glass, ease) both; }
}
@keyframes s-vt-out { to { opacity: 0; transform: translateY(-8px); } }
@keyframes s-vt-in { from { opacity: 0; transform: translateY(12px); } }
/* The bar and the tab bar are the app frame: they stay put while the page
   under them changes, which is the whole difference between an application and
   a series of documents. */
.sinstud .s-top { view-transition-name: s-chrome; }
.sinstud .s-tabs { view-transition-name: s-tabs; }
.sinstud .s-orb { view-transition-name: s-orb; }

/* A film of grain over everything. Print has tooth; a screen has none, and at
   this scale of type the flat black reads as empty rather than as paper. */
.sinstud::after {
  content: ''; position: fixed; inset: 0; z-index: 1; pointer-events: none;
  opacity: .028; mix-blend-mode: overlay;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='140' height='140'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='.85' numOctaves='3'/%3E%3C/filter%3E%3Crect width='140' height='140' filter='url(%23n)'/%3E%3C/svg%3E");
}

/* ═══════════════════════════════════════════════════ fracture, and aurora
 *
 * The mechanism is from Gabriel's Claude Design piece; the palette is not.
 * Its oklch rainbow is a second design system, and the rule here is that new
 * colour outside the token set is rejected on sight — so the crack lights in
 * ice and glass, and the aurora runs the site's own blue, amber and white. The
 * motion, the timings and the shard geometry are kept, because that is the part
 * that was designed.
 *
 * Injected on press rather than sitting in every button's markup: the layer is
 * nine elements and would otherwise be in the DOM of every control on the site
 * for the one second a decade it is used. It is removed when it finishes.
 */
.sinstud .s-frac {
  position: absolute; inset: 0; z-index: 3; pointer-events: none;
  border-radius: inherit; overflow: hidden;
}
.sinstud .s-frac i {
  position: absolute; inset: 0; display: block;
  animation: s-shard 900ms cubic-bezier(.2,.85,.25,1) both;
}
/* Six wedges out of one centre — a fracture has a cause, so every piece
   radiates from the same strike rather than being scattered independently. */
.sinstud .s-frac i:nth-child(1) { clip-path: polygon(0% 0%, 30% 0%, 22% 48%, 0% 55%); background: linear-gradient(150deg, rgba(255,255,255,0.4), rgba(255,255,255,0.06));  --tx: -16px; --ty: -20px; --rot: -7deg; }
.sinstud .s-frac i:nth-child(2) { clip-path: polygon(30% 0%, 58% 0%, 50% 52%, 22% 48%); background: linear-gradient(170deg, rgba(255,255,255,0.34), rgba(255,255,255,0.04)); --tx: 2px;   --ty: -26px; --rot: 4deg;  animation-delay: 20ms; }
.sinstud .s-frac i:nth-child(3) { clip-path: polygon(58% 0%, 100% 0%, 100% 42%, 50% 52%); background: linear-gradient(200deg, rgba(255,255,255,0.38), rgba(255,255,255,0.05)); --tx: 20px; --ty: -18px; --rot: 8deg;  animation-delay: 40ms; }
.sinstud .s-frac i:nth-child(4) { clip-path: polygon(0% 55%, 22% 48%, 26% 100%, 0% 100%); background: linear-gradient(20deg, rgba(255,255,255,0.3), rgba(255,255,255,0.04));  --tx: -20px; --ty: 16px;  --rot: 6deg;  animation-delay: 30ms; }
.sinstud .s-frac i:nth-child(5) { clip-path: polygon(22% 48%, 50% 52%, 60% 100%, 26% 100%); background: linear-gradient(0deg, rgba(255,255,255,0.32), rgba(255,255,255,0.05)); --tx: 0px; --ty: 24px; --rot: -5deg; animation-delay: 55ms; }
.sinstud .s-frac i:nth-child(6) { clip-path: polygon(50% 52%, 100% 42%, 100% 100%, 60% 100%); background: linear-gradient(340deg, rgba(255,255,255,0.36), rgba(255,255,255,0.05)); --tx: 22px; --ty: 20px; --rot: 9deg; animation-delay: 15ms; }
@keyframes s-shard {
  0%   { transform: translate(0,0) rotate(0) scale(1); opacity: 0; }
  10%  { opacity: 1; }
  55%  { transform: translate(var(--tx), var(--ty)) rotate(var(--rot)) scale(1.05); opacity: .9; }
  100% { transform: translate(0,0) rotate(0) scale(1); opacity: 0; }
}

.sinstud .s-frac b {
  position: absolute; left: 50%; top: 50%; height: 2px; display: block;
  transform-origin: 50% 50%;
  animation: s-crack 820ms cubic-bezier(.1,.9,.2,1) both;
}
/* The crack colours are the file's own oklch, not the site's tokens. */
.sinstud .s-frac b:nth-of-type(1) { width: 130%; --a: 8deg;
  background: linear-gradient(90deg, transparent, oklch(0.96 0.06 210), #ffffff, oklch(0.94 0.1 300), transparent);
  box-shadow: 0 0 14px oklch(0.85 0.16 250 / 0.9); }
.sinstud .s-frac b:nth-of-type(2) { width: 90%; height: 1.5px; --a: -58deg; animation-delay: 60ms;
  background: linear-gradient(90deg, transparent, #ffffff, oklch(0.9 0.14 160), transparent);
  box-shadow: 0 0 12px oklch(0.86 0.15 170 / 0.8); }
.sinstud .s-frac b:nth-of-type(3) { width: 76%; height: 1.5px; --a: 62deg; animation-delay: 100ms;
  background: linear-gradient(90deg, transparent, oklch(0.92 0.13 300), #ffffff, transparent);
  box-shadow: 0 0 12px oklch(0.85 0.16 300 / 0.8); }
@keyframes s-crack {
  0%   { transform: translate(-50%,-50%) rotate(var(--a)) scaleX(0); opacity: 0; }
  12%  { opacity: 1; }
  38%  { transform: translate(-50%,-50%) rotate(var(--a)) scaleX(1); opacity: 1; }
  100% { transform: translate(-50%,-50%) rotate(var(--a)) scaleX(1); opacity: 0; }
}
@media (prefers-reduced-motion: reduce) { .sinstud .s-frac { display: none; } }

/* The aurora, in the file's own colours, positioned by the script at the centre
 * of the star that was pressed. It used to be appended to the section and
 * anchored at its 50%/50%, which on a full-width block is a point in open page
 * — the burst came out of nowhere instead of out of the button. */
.sinstud .s-aurora { position: absolute; width: 0; height: 0; z-index: 60; pointer-events: none; }
.sinstud .s-aurora u, .sinstud .s-aurora s {
  position: absolute; left: 50%; top: 50%; display: block;
  border-radius: 50%; mix-blend-mode: screen; opacity: 0; text-decoration: none;
}
.sinstud .s-aurora u:nth-of-type(1) {
  width: clamp(240px,58vw,620px); height: clamp(240px,58vw,620px); filter: blur(44px);
  background: conic-gradient(from 0deg, oklch(0.82 0.22 210), oklch(0.86 0.2 155),
    oklch(0.8 0.24 295), oklch(0.88 0.18 85), oklch(0.82 0.22 210));
  animation: s-aurora-burst 1200ms cubic-bezier(.14,.86,.24,1) forwards; --r: 0deg; --s: 2.1;
}
.sinstud .s-aurora u:nth-of-type(2) {
  width: clamp(200px,46vw,520px); height: clamp(200px,46vw,520px); filter: blur(30px);
  background: conic-gradient(from 140deg, oklch(0.84 0.2 175), transparent 35%,
    oklch(0.82 0.23 265), transparent 70%, oklch(0.84 0.2 175));
  animation: s-aurora-burst 1150ms cubic-bezier(.14,.86,.24,1) 60ms forwards; --r: 40deg; --s: 2.6;
}
.sinstud .s-aurora s:nth-of-type(1) {
  width: clamp(320px,84vw,860px); height: clamp(90px,20vw,200px); filter: blur(26px);
  background: linear-gradient(90deg, transparent, oklch(0.86 0.2 195 / 0.85),
    oklch(0.9 0.16 130 / 0.75), oklch(0.84 0.22 290 / 0.8), transparent);
  animation: s-aurora-veil 1250ms cubic-bezier(.14,.86,.24,1) 40ms forwards; --r: -14deg; --s: 1.5;
}
.sinstud .s-aurora s:nth-of-type(2) {
  width: clamp(280px,70vw,720px); height: clamp(70px,16vw,160px); filter: blur(22px);
  background: linear-gradient(90deg, transparent, oklch(0.9 0.17 160 / 0.7),
    oklch(0.86 0.2 240 / 0.8), transparent);
  animation: s-aurora-veil 1200ms cubic-bezier(.14,.86,.24,1) 110ms forwards; --r: 26deg; --s: 1.7;
}
@keyframes s-aurora-burst {
  0%   { transform: translate(-50%,-50%) rotate(var(--r)) scale(.22); opacity: 0; }
  14%  { opacity: .95; }
  100% { transform: translate(-50%,-50%) rotate(calc(var(--r) + 55deg)) scale(var(--s)); opacity: 0; }
}
@keyframes s-aurora-veil {
  0%   { transform: translate(-50%,-50%) rotate(var(--r)) scaleX(.2) scaleY(.5); opacity: 0; }
  18%  { opacity: .85; }
  100% { transform: translate(-50%,-50%) rotate(calc(var(--r) - 30deg)) scaleX(var(--s)) scaleY(1.6); opacity: 0; }
}
@media (prefers-reduced-motion: reduce) { .sinstud .s-aurora { display: none; } }

/* ─────────────────────────────────────────────────────────────── the stars */
.sinstud .s-rate { margin: 54px 0 0; position: relative; }
.sinstud .s-stars { display: flex; gap: 10px; margin-top: 16px; position: relative; }
.sinstud .s-star {
  width: 46px; height: 46px; padding: 0;
  display: grid; place-items: center;
  -webkit-tap-highlight-color: transparent;
  /* Clipped so the fracture stays inside the glass, which is where it belongs.
     The aurora is a sibling of the stars, not a child, so this does not cut it. */
  overflow: hidden;
}
.sinstud .s-star svg { position: relative; z-index: 1; }
.sinstud .s-star svg { width: 21px; height: 21px; display: block;
  fill: none; stroke: rgba(255,255,255,.72); stroke-width: 1.6;
  transition: fill .25s var(--ease-glass, ease), stroke .25s ease, transform .25s var(--ease-glass, ease); }
.sinstud .s-star[aria-checked="true"] svg { fill: #ffffff; stroke: #ffffff; }
.sinstud .s-star:hover svg { transform: scale(1.12); }
.sinstud .s-rate-note { margin-top: 12px; }

/* ═══════════════════════════════════════════════════════ the phone, as an app
 *
 * Everything in this block is under a max-width query and stops at the tablet.
 * The desktop layout is unchanged: this is the phone being a different thing
 * rather than the same thing narrower.
 */
@media (max-width: 47.99rem) {
  /* `main` becomes the ordering context. The page head and the search bar have
     to sit above the rest, and they are a block inside the body and a control
     emitted after it — nothing in the DOM puts them next to each other, so
     order does. */
  .sinstud main { display: flex; flex-direction: column; }
  .sinstud .s-pagehead { order: -2; }
  .sinstud .s-appsearch { order: -1; }

  /* Title and standfirst range right, against a mark that ranges left. The
     asymmetry is the point: two anchors at opposite corners reads as an
     application's chrome, where a centred stack reads as a document's cover. */
  .sinstud .s-pagehead {
    text-align: right; padding-top: 4px;
  }
  .sinstud .s-pagehead .s-lede { margin-left: auto; margin-right: 0; }
  .sinstud .s-pagehead .s-rule { margin-top: 22px; }
  .sinstud .s-pagetitle { font-size: clamp(34px, 11vw, 46px); }

  /* Full width, and the first thing under the title — where a thumb reaches
     without moving the hand. */
  .sinstud .s-appsearch {
    display: flex; align-items: center; gap: 10px;
    width: 100%; margin: 18px 0 4px; padding: 0 16px;
    height: 46px; box-sizing: border-box; border-radius: 999px;
    background: linear-gradient(180deg,
      rgba(255,255,255,0.14) 0%, rgba(255,255,255,0.06) 45%, rgba(255,255,255,0.03) 100%);
    backdrop-filter: blur(22px) saturate(180%);
    -webkit-backdrop-filter: blur(22px) saturate(180%);
    box-shadow:
      inset 0 1px 0 rgba(255,255,255,0.4),
      inset 0 0 0 1px rgba(255,255,255,0.16),
      0 10px 26px rgba(4,6,16,0.45);
  }
  .sinstud .s-appsearch svg { width: 17px; height: 17px; flex: none; color: rgba(255,255,255,.6); }
  .sinstud .s-appsearch input {
    flex: 1; min-width: 0; background: none; border: 0; outline: none;
    color: #fff; font-family: var(--font-body);
    /* 16px or iOS zooms the whole page when the field takes focus. */
    font-size: 16px;
  }
  .sinstud .s-appsearch input::placeholder { color: rgba(255,255,255,.45); }
  .sinstud .s-appsearch input::-webkit-search-cancel-button { filter: invert(1) opacity(.5); }

  /* A page that opens on a hero has no page head, so the search bar would be
     the first thing under a full-screen video. It belongs to the pages that
     have a title. */
  .sinstud.s-shell-bleed .s-appsearch { display: none; }

  /* Tighter between blocks than the desktop wants. A feed is read by
     scrolling, and 96px of ground between the search and the first item is a
     gap the thumb has to cross for nothing. */
  .sinstud .s-block { margin-top: 40px; }
  .sinstud .s-grid { gap: 30px 18px; margin-top: 18px; }
}
@media (min-width: 48rem) { .sinstud .s-appsearch { display: none; } }
