/* ==========================================================================
   shib.me - Layout
   ========================================================================== */

.wrap {
    width: 100%;
    max-width: 920px;
    margin: 0 auto;
    padding: 0 var(--gutter);
}

/* ==========================================================================
   Topbar
   ========================================================================== */

.topbar {
    position: sticky;
    top: 0;
    z-index: 50;
    display: flex;
    align-items: center;
    gap: 12px;
    padding: 12px var(--gutter);
    background: color-mix(in srgb, var(--bg-color) 82%, transparent);
    backdrop-filter: saturate(180%) blur(14px);
    -webkit-backdrop-filter: saturate(180%) blur(14px);
    border-bottom: 1px solid transparent;
    transition: border-color 0.2s var(--ease);
}

.topbar.is-scrolled {
    border-bottom-color: var(--border-color);
}

/* "Shib" reversed out of a gradient block, "Me" outside it. Same structure as
   the old ShibMe wordmark, brand colours instead of solid black. */
.brand {
    display: inline-flex;
    align-items: baseline;
    font-size: 18px;
    font-weight: 800;
    letter-spacing: -0.02em;
    text-decoration: none;
    margin-right: auto;
}

/* The one place --brand-gradient carries text. Safe here because it is a solid
   fill behind 800-weight at 18px, not body copy. */
.brand .shib {
    padding: 1px 6px 2px;
    border-radius: 6px;
    color: #fff;
    background: var(--brand-gradient);
}

.brand .me {
    padding-left: 5px;
    color: var(--text-color);
}

.topbar-nav {
    display: flex;
    gap: 4px;
    margin-right: 4px;
}

.topbar-nav a {
    padding: 6px 10px;
    border-radius: var(--radius-pill);
    color: var(--text-muted);
    font-size: 13.5px;
    font-weight: 500;
    text-decoration: none;
    transition: color 0.15s var(--ease), background 0.15s var(--ease);
}

.topbar-nav a:hover {
    color: var(--text-color);
    background: var(--surface-2);
}

.icon-btn {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 34px;
    height: 34px;
    padding: 0;
    color: var(--text-muted);
    background: transparent;
    border: 1px solid var(--border-color);
    border-radius: var(--radius-pill);
    cursor: pointer;
    transition: color 0.15s var(--ease), border-color 0.15s var(--ease), background 0.15s var(--ease);
}

.icon-btn:hover {
    color: var(--text-color);
    border-color: var(--border-strong);
    background: var(--surface-2);
}

.icon-btn svg {
    width: 17px;
    height: 17px;
    fill: currentColor;
}

/* The toggle shows the theme you'd switch *to*. JS swaps which icon is hidden;
   with JS off, neither is hidden and the button is removed from the flow. */
.theme-toggle .moon {
    display: none;
}

[data-theme="dark"] .theme-toggle .moon {
    display: block;
}

[data-theme="dark"] .theme-toggle .sun {
    display: none;
}

html:not([data-theme]) .theme-toggle {
    display: none;
}

/* ==========================================================================
   Sections
   ========================================================================== */

section {
    padding: 72px 0 8px;
}

.section-label {
    display: flex;
    align-items: center;
    gap: 12px;
    font-family: var(--font-mono);
    font-size: 12px;
    font-weight: 600;
    letter-spacing: 0.14em;
    text-transform: uppercase;
    color: var(--text-faint);
    margin-bottom: 14px;
}

.section-label::after {
    content: "";
    flex: 1;
    height: 1px;
    background: var(--border-color);
}

.section-title {
    font-size: clamp(26px, 4vw, 34px);
    font-weight: 700;
    margin-bottom: 10px;
}

.section-intro {
    color: var(--text-muted);
    max-width: var(--measure);
    margin-bottom: 30px;
}

/* Second-level divider, used once to split the public projects from the
   internal work. The label under a section title needs no space above it,
   this one does. */
.grid + .section-label {
    margin-top: 54px;
}

/* ==========================================================================
   Hero
   ========================================================================== */

.hero {
    padding: clamp(44px, 8vw, 84px) 0 24px;
}

.hero-top {
    display: flex;
    align-items: center;
    gap: clamp(20px, 4vw, 34px);
    margin-bottom: 30px;
}

.hero-portrait {
    flex: none;
    width: clamp(96px, 16vw, 132px);
    height: clamp(96px, 16vw, 132px);
    border-radius: 50%;
    object-fit: cover;
    border: 3px solid var(--surface-color);
    box-shadow: var(--shadow-md);
}

/* The name carries the display weight. Shib and Me are picked out so the
   ShibMe wordmark reads out of the full name, the same split the topbar brand
   makes with a gradient block. */
.hero-name {
    font-size: clamp(34px, 7vw, 58px);
    font-weight: 800;
    letter-spacing: -0.03em;
}

.hero-name .hl {
    background: var(--accent-ramp);
    -webkit-background-clip: text;
    background-clip: text;
    -webkit-text-fill-color: transparent;
    color: var(--brand-2);
}

.hero-tagline {
    margin-top: 12px;
    font-size: clamp(16px, 2.3vw, 20px);
    font-weight: 500;
    color: var(--text-muted);
    max-width: var(--measure);
}

/* The gradient is the emphasis, so the italics go. --accent-ramp rather than
   --brand-gradient, because the ramp is the one that survives a light
   background. */
.hero-tagline em {
    font-style: normal;
    background: var(--accent-ramp);
    -webkit-background-clip: text;
    background-clip: text;
    -webkit-text-fill-color: transparent;
    color: var(--brand-2);
}

/* Forced-colours modes drop the gradient. Without this the highlighted chunks go
   invisible, the name reads "ly eran" and the tagline reads "I keep for a
   living". */
@media (forced-colors: active) {

    .hero-name .hl,
    .hero-tagline em {
        background: none;
        -webkit-text-fill-color: currentColor;
    }
}

.hero-body {
    max-width: var(--measure);
    font-size: clamp(16px, 2vw, 18px);
    color: var(--text-muted);
}

.hero-body strong {
    color: var(--text-color);
    font-weight: 600;
}

.hero-body p + p {
    margin-top: 14px;
}

/* ==========================================================================
   Buttons
   ========================================================================== */

.cta-row {
    display: flex;
    flex-wrap: wrap;
    gap: 10px;
    margin-top: 26px;
}

.btn {
    display: inline-flex;
    align-items: center;
    gap: 8px;
    padding: 11px 20px;
    font-size: 14.5px;
    font-weight: 600;
    text-decoration: none;
    border: 1px solid var(--border-color);
    border-radius: var(--radius-pill);
    background: var(--surface-color);
    box-shadow: var(--shadow-sm);
    transition: transform 0.15s var(--ease), border-color 0.15s var(--ease), box-shadow 0.15s var(--ease);
}

.btn svg {
    width: 16px;
    height: 16px;
    fill: currentColor;
}

.btn:hover {
    transform: translateY(-1px);
    border-color: var(--border-strong);
    box-shadow: var(--shadow-md);
}

/* Deliberately not --brand-gradient: white text over #00ddff is about 1.6:1.
   This ramp keeps white above 5:1 at every point along it. */
.btn-primary {
    color: #fff;
    background: linear-gradient(135deg, #0072b8, #0044ff);
    border-color: transparent;
}

.cta-note {
    margin-top: 14px;
    font-size: 13.5px;
    color: var(--text-faint);
    max-width: 60ch;
}

.cta-note code {
    color: var(--text-muted);
}

/* ==========================================================================
   Cards
   ========================================================================== */

.grid {
    display: grid;
    gap: 16px;
    grid-template-columns: repeat(auto-fit, minmax(240px, 1fr));
}

/* Four cards want 2×2, not 3-then-an-orphan. */
.grid-2 {
    grid-template-columns: repeat(auto-fit, minmax(min(100%, 340px), 1fr));
}

.card {
    padding: 22px;
    background: var(--surface-color);
    border: 1px solid var(--border-color);
    border-radius: var(--radius-lg);
    box-shadow: var(--shadow-sm);
    transition: transform 0.18s var(--ease), box-shadow 0.18s var(--ease), border-color 0.18s var(--ease);
}

.card h3 {
    font-size: 17px;
    font-weight: 700;
    margin-bottom: 8px;
}

.card p {
    font-size: 14.5px;
    color: var(--text-muted);
}

/* Project cards get a gradient hairline on hover. */
.card-project:hover {
    transform: translateY(-2px);
    border-color: var(--border-strong);
    box-shadow: var(--shadow-md);
}

.card-project .card-head {
    display: flex;
    /* Centred, not baseline-aligned: the logo tile is taller than its heading. */
    align-items: center;
    justify-content: space-between;
    gap: 12px;
    margin-bottom: 4px;
}

.card-title {
    display: flex;
    align-items: center;
    gap: 10px;
}

/* .card h3 carries a bottom margin, which offsets it inside a centred flex row. */
.card-title h3 {
    margin-bottom: 0;
}

/* The project marks sit on a tile rather than straight on the card. --surface-2
   already follows the theme, so the tile is pale in light and dark in dark with no
   second declaration. The inset highlight is invisible on the pale tile and gives
   the dark one a lit top edge. */
.card-logo {
    flex: none;
    display: grid;
    place-items: center;
    width: 34px;
    height: 34px;
    border-radius: 10px;
    background: var(--surface-2);
    border: 1px solid var(--border-color);
    box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.06);
    transition: border-color 0.18s var(--ease), box-shadow 0.18s var(--ease);
}

.card-logo img {
    width: 22px;
    height: 22px;
    object-fit: contain;
    transition: transform 0.18s var(--ease);
}

/* Dark mode wants a stronger hairline, or the tile barely reads against the card.
   Spelled out twice, the way base.css does it, so visitors with JavaScript off get
   it too. */
[data-theme="dark"] .card-logo {
    border-color: var(--border-strong);
}

@media (prefers-color-scheme: dark) {
    :root:not([data-theme]) .card-logo {
        border-color: var(--border-strong);
    }
}

.card-project:hover .card-logo {
    border-color: var(--brand-1);
    /* Same blue as --bg-accent's radial, the only other bare rgba on the site. */
    box-shadow: 0 0 0 3px rgba(0, 132, 255, 0.14);
}

.card-project:hover .card-logo img {
    transform: scale(1.07);
}

.card-project h3 a {
    text-decoration: none;
    background-image: var(--brand-gradient);
    background-repeat: no-repeat;
    background-size: 0% 2px;
    background-position: 0 100%;
    transition: background-size 0.25s var(--ease);
}

.card-project:hover h3 a {
    background-size: 100% 2px;
}

.card-domain {
    font-family: var(--font-mono);
    font-size: 12px;
    color: var(--text-faint);
    white-space: nowrap;
}

.card-tagline {
    font-size: 15px;
    color: var(--text-color);
    font-weight: 500;
    margin-bottom: 10px;
}

.card-meta {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 8px;
    margin-top: 16px;
    padding-top: 14px;
    border-top: 1px solid var(--border-color);
    font-size: 13px;
}

.card-meta a {
    color: var(--text-muted);
    text-decoration: none;
    font-weight: 600;
}

.card-meta a:hover {
    color: var(--text-color);
}

.chip {
    display: inline-flex;
    align-items: center;
    gap: 5px;
    padding: 3px 9px;
    border: 1px solid var(--border-color);
    border-radius: var(--radius-pill);
    background: var(--surface-2);
    font-family: var(--font-mono);
    font-size: 11.5px;
    font-weight: 600;
    color: var(--text-muted);
}

.tags {
    display: flex;
    flex-wrap: wrap;
    gap: 6px;
    margin-top: 12px;
}

.tag {
    padding: 3px 9px;
    border-radius: var(--radius-pill);
    background: var(--surface-2);
    font-size: 11.5px;
    font-weight: 600;
    color: var(--text-faint);
    letter-spacing: 0.02em;
}

/* ==========================================================================
   Prose blocks (internal work, war stories)
   ========================================================================== */

.movement {
    position: relative;
    padding-left: 24px;
    margin-bottom: 34px;
}

.movement::before {
    content: "";
    position: absolute;
    left: 0;
    top: 6px;
    bottom: 6px;
    width: 2px;
    border-radius: 2px;
    background: var(--brand-gradient);
    opacity: 0.55;
}

.movement h3 {
    font-size: 18px;
    font-weight: 700;
    margin-bottom: 4px;
}

.movement .when {
    font-family: var(--font-mono);
    font-size: 12px;
    letter-spacing: 0.08em;
    text-transform: uppercase;
    color: var(--text-faint);
    margin-bottom: 10px;
}

.movement p {
    max-width: var(--measure);
    color: var(--text-muted);
}

.movement p + p {
    margin-top: 12px;
}

.movement strong {
    color: var(--text-color);
    font-weight: 600;
}

/* Pull-quote, used for the token exchange design and the 10 Commandments. */
.pull {
    /* Line the inner text up with the prose measure around it. */
    max-width: calc(var(--measure) + 44px);
    margin: 18px 0;
    padding: 18px 22px;
    background: var(--surface-color);
    border: 1px solid var(--border-color);
    border-left: 3px solid var(--brand-2);
    border-radius: 0 var(--radius-md) var(--radius-md) 0;
    box-shadow: var(--shadow-sm);
}

.pull p {
    color: var(--text-color);
    font-size: 15px;
}

.pull .pull-label {
    display: block;
    font-family: var(--font-mono);
    font-size: 11.5px;
    font-weight: 600;
    letter-spacing: 0.12em;
    text-transform: uppercase;
    color: var(--text-faint);
    margin-bottom: 8px;
}

/* War stories */
.story {
    padding: 24px;
    background: var(--surface-color);
    border: 1px solid var(--border-color);
    border-radius: var(--radius-lg);
    box-shadow: var(--shadow-sm);
}

.story + .story {
    margin-top: 16px;
}

.story h3 {
    font-size: 19px;
    font-weight: 700;
    margin-bottom: 14px;
}

.story dl {
    margin: 0;
}

.story dt {
    font-family: var(--font-mono);
    font-size: 11.5px;
    font-weight: 600;
    letter-spacing: 0.12em;
    text-transform: uppercase;
    color: var(--text-faint);
    margin-bottom: 4px;
}

.story dd {
    margin: 0 0 14px;
    color: var(--text-muted);
    max-width: var(--measure);
}

.story dd:last-child {
    margin-bottom: 0;
}

.story dd strong {
    color: var(--text-color);
    font-weight: 600;
}

.disclaimer {
    padding: 14px 18px;
    margin-bottom: 24px;
    border: 1px dashed var(--border-strong);
    border-radius: var(--radius-md);
    font-size: 14.5px;
    color: var(--text-muted);
    max-width: var(--measure);
}

/* ==========================================================================
   Talks
   ========================================================================== */

.talks li {
    display: flex;
    flex-wrap: wrap;
    align-items: baseline;
    gap: 6px 14px;
    padding: 16px 0;
    border-top: 1px solid var(--border-color);
}

.talks li:first-child {
    border-top: 0;
    padding-top: 0;
}

.talks .talk-when {
    flex: none;
    width: 108px;
    font-family: var(--font-mono);
    font-size: 12.5px;
    color: var(--text-faint);
    letter-spacing: 0.04em;
}

.talks .talk-what {
    flex: 1 1 260px;
}

.talks .talk-title {
    font-weight: 600;
}

.talks .talk-what a {
    font-weight: 600;
    text-decoration: none;
    border-bottom: 1px solid var(--border-strong);
}

.talks .talk-what a:hover {
    border-bottom-color: var(--brand-2);
}

.talks .talk-what p {
    font-size: 14px;
    color: var(--text-muted);
    margin-top: 3px;
}

/* ==========================================================================
   Timeline
   ========================================================================== */

.timeline li {
    display: flex;
    flex-wrap: wrap;
    gap: 4px 20px;
    padding: 18px 0;
    border-top: 1px solid var(--border-color);
}

.timeline li:first-child {
    border-top: 0;
}

.timeline .tl-when {
    flex: none;
    /* Wide enough that "May 2016 – Jul 2022" stays on one line. */
    width: 158px;
    font-family: var(--font-mono);
    font-size: 12.5px;
    color: var(--text-faint);
    padding-top: 2px;
    letter-spacing: 0.02em;
}

.timeline .tl-what {
    flex: 1 1 280px;
}

.timeline h3 {
    font-size: 16.5px;
    font-weight: 700;
}

.timeline .tl-role {
    font-size: 14px;
    color: var(--text-color);
    font-weight: 500;
    margin: 3px 0 6px;
}

.timeline .tl-ladder {
    font-size: 13.5px;
    color: var(--text-faint);
    margin: 3px 0 6px;
}

.timeline p {
    font-size: 14.5px;
    color: var(--text-muted);
    max-width: var(--measure);
}

/* Same treatment the talks list uses, so links in the timeline prose do not fall
   back to the browser default underline. */
.timeline .tl-what a {
    font-weight: 600;
    text-decoration: none;
    border-bottom: 1px solid var(--border-strong);
}

.timeline .tl-what a:hover {
    border-bottom-color: var(--brand-2);
}

.education {
    margin-top: 26px;
    padding-top: 18px;
    border-top: 1px solid var(--border-color);
    font-size: 14.5px;
    color: var(--text-muted);
}

/* ==========================================================================
   Contact & footer
   ========================================================================== */

.contact-card {
    padding: clamp(24px, 4vw, 36px);
    background: var(--surface-color);
    border: 1px solid var(--border-color);
    border-radius: var(--radius-lg);
    box-shadow: var(--shadow-md);
}

.contact-card h2 {
    font-size: clamp(22px, 3.4vw, 28px);
    font-weight: 700;
    margin-bottom: 8px;
}

.contact-card > p {
    color: var(--text-muted);
    max-width: var(--measure);
}

.codeblock {
    display: flex;
    align-items: center;
    gap: 12px;
    margin-top: 22px;
    padding: 12px 14px;
    background: var(--surface-2);
    border: 1px solid var(--border-color);
    border-radius: var(--radius-md);
}

/* The command scrolls inside its own track rather than inside .codeblock, so
   the copy button stays on screen when the command is wider than the box.
   min-width is the load-bearing part: a flex item defaults to min-width: auto
   and refuses to shrink below its content, which is what pushed the button
   out of view on narrow screens. */
.codeblock code {
    flex: 1;
    min-width: 0;
    overflow-x: auto;
    font-size: 13px;
    white-space: nowrap;
    color: var(--text-color);
}

.codeblock code .prompt {
    color: var(--text-faint);
    user-select: none;
}

.copy-btn {
    flex: none;
    padding: 5px 12px;
    font-family: var(--font-mono);
    font-size: 11.5px;
    font-weight: 600;
    color: var(--text-muted);
    background: var(--surface-color);
    border: 1px solid var(--border-color);
    border-radius: var(--radius-pill);
    cursor: pointer;
    transition: color 0.15s var(--ease), border-color 0.15s var(--ease);
}

.copy-btn:hover {
    color: var(--text-color);
    border-color: var(--border-strong);
}

.copy-btn.done {
    color: var(--success-color);
    border-color: var(--success-color);
}

/* No clipboard API / no JS: the button is pointless, so hide it. */
html:not(.js) .copy-btn {
    display: none;
}

footer {
    margin-top: 72px;
    padding: 30px 0 48px;
    border-top: 1px solid var(--border-color);
}

.footer-note {
    font-size: 13.5px;
    color: var(--text-faint);
    /* The measure still applies, so the auto margins are what put the centred
       text in the middle of the page rather than in the middle of a
       left-aligned box. */
    max-width: var(--measure);
    margin: 0 auto;
    text-align: center;
}

.footer-note p + p {
    margin-top: 6px;
}

.footer-note strong {
    color: var(--text-muted);
    font-weight: 600;
}

/* ==========================================================================
   Responsive
   ========================================================================== */

@media (max-width: 720px) {
    /* The nav drops to its own full-width row under the brand. */
    .topbar {
        flex-wrap: wrap;
        row-gap: 8px;
        padding-bottom: 8px;
    }

    /* A scrollable strip of pills. It bleeds to both screen edges so a clipped
       last pill is the signal that there is more to the right, which saves
       needing a gradient or an arrow. Pills carry a resting surface because
       there is no hover on a touch screen. */
    .topbar-nav {
        display: flex;
        order: 3;
        flex: 1 0 100%;
        margin: 0 calc(-1 * var(--gutter));
        padding: 0 var(--gutter) 2px;
        overflow-x: auto;
        scrollbar-width: none;
        scroll-snap-type: x proximity;
        -webkit-overflow-scrolling: touch;
    }

    .topbar-nav::-webkit-scrollbar {
        display: none;
    }

    .topbar-nav a {
        flex: none;
        padding: 9px 14px;
        white-space: nowrap;
        scroll-snap-align: start;
        background: var(--surface-2);
        border: 1px solid var(--border-color);
    }

    /* The nav row takes the topbar from 58px to about 100px, so deep-linked
       headings need more clearance than the 88px set in base.css. */
    html {
        scroll-padding-top: 112px;
    }

    /* 34px clears WCAG 2.5.8 AA but sits under Apple's 44px guidance. Growing
       the buttons would add height to a sticky bar that just gained a row, so
       the hit area grows and the visual size stays put. The two topbar icons
       are 46px apart centre to centre, so these do not overlap. */
    .icon-btn {
        position: relative;
    }

    .icon-btn::after {
        content: "";
        position: absolute;
        top: 50%;
        left: 50%;
        transform: translate(-50%, -50%);
        width: 44px;
        height: 44px;
    }

    .hero-top {
        flex-direction: column;
        align-items: flex-start;
        gap: 18px;
    }

    .talks .talk-when,
    .timeline .tl-when {
        width: auto;
    }

    section {
        padding-top: 56px;
    }
}

/* Small phones, where a 24px gutter costs measure that the text needs more
   than the margins do. */
@media (max-width: 480px) {
    :root {
        --gutter: 18px;
    }

    .card,
    .story {
        padding: 18px;
    }

    .pull {
        padding: 16px 18px;
    }

    .movement {
        padding-left: 18px;
    }
}
